wrapper_3.5.26_src/build32.sh100755 0 0 324 12440202300 13114 0ustar 0 0 #!/bin/sh BUILDFILE="`pwd`/`dirname $0`/build.xml" echo "--------------------" echo "Wrapper Build System" echo "using $BUILDFILE" echo "--------------------" "$ANT_HOME/bin/ant" -f "$BUILDFILE" -Dbits=32 $@ wrapper_3.5.26_src/build64.sh100755 0 0 324 12440202300 13121 0ustar 0 0 #!/bin/sh BUILDFILE="`pwd`/`dirname $0`/build.xml" echo "--------------------" echo "Wrapper Build System" echo "using $BUILDFILE" echo "--------------------" "$ANT_HOME/bin/ant" -f "$BUILDFILE" -Dbits=64 $@ wrapper_3.5.26_src/build/ 40755 0 0 0 12440202300 12334 5ustar 0 0 wrapper_3.5.26_src/doc/ 40755 0 0 0 12440202301 12003 5ustar 0 0 wrapper_3.5.26_src/src/ 40755 0 0 0 12440202300 12024 5ustar 0 0 wrapper_3.5.26_src/src/bin/ 40755 0 0 0 12440202300 12574 5ustar 0 0 wrapper_3.5.26_src/src/c/ 40755 0 0 0 12440202301 12247 5ustar 0 0 wrapper_3.5.26_src/src/conf/ 40755 0 0 0 12440202301 12752 5ustar 0 0 wrapper_3.5.26_src/src/java/ 40755 0 0 0 12440202300 12745 5ustar 0 0 wrapper_3.5.26_src/src/java/org/ 40755 0 0 0 12440202300 13534 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/ 40755 0 0 0 12440202300 16602 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/ 40755 0 0 0 12440202301 20263 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/ 40755 0 0 0 12440202301 21207 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/ 40755 0 0 0 12440202301 22153 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/ 40755 0 0 0 12440202301 21404 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/jmx/ 40755 0 0 0 12440202301 21061 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/resources/ 40755 0 0 0 12440202301 22275 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/security/ 40755 0 0 0 12440202301 22132 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/ 40755 0 0 0 12440202301 21242 5ustar 0 0 wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test2/ 40755 0 0 0 12440202301 21324 5ustar 0 0 wrapper_3.5.26_src/src/test/ 40755 0 0 0 12440202300 13003 5ustar 0 0 wrapper_3.5.26_src/src/test/org/ 40755 0 0 0 12440202300 13572 5ustar 0 0 wrapper_3.5.26_src/src/test/org/tanukisoftware/ 40755 0 0 0 12440202300 16640 5ustar 0 0 wrapper_3.5.26_src/src/test/org/tanukisoftware/wrapper/ 40755 0 0 0 12440202301 20321 5ustar 0 0 wrapper_3.5.26_src/README_de.txt100644 0 0 13724 12440202301 13530 0ustar 0 0 ----------------------------------------------------------------------------- Java Service Wrapper Community Edition 3.5.26 Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved. http://wrapper.tanukisoftware.com ----------------------------------------------------------------------------- Zusammenfassung: 1. Was ist der Java Service Wrapper? 2. Dokumentation 3. Installation 4. Lizenzoptionen 5. Wie zu erwerben? 6. Aktualisieren 7. FAQ 8. Support 9. Systemvoraussetzungen 1. Was ist der Java Service Wrapper? ----------------------------------------------------------------------------- Der Java Service Wrapper ist eine Anwendung die aus dem Wunsch heraus erstellt worden ist, eine Vielzahl von Java bedingten Problem und Einschränkungen zu beheben. Einige der Möglichkeiten des Wrappers sind: * Eine Javaanwendung als Windows Dienst und Unix Daemon zu starten * Erhöhung der Zuverlässigkeit von Javaanwendungen. * Automatische Crash-, Stillstand- und Deadlock-Erkennung und Wiederherstellung * On Demand Neustarts * Standard, Out-of-the-Box Scripting * Flexible Cross-Platform Konfiguration * Vereinfachung der Installation von Javaanwenungen * Logging * Und vieles mehr... Bitte gehen Sie auf unsere Downloadseite für mehr Details: => http://wrapper.tanukisoftware.com/doc/german/download.jsp Für weitere Informationen gehen Sie bitte auf: => http://wrapper.tanukisoftware.com/doc/german/introduction.html 2. Dokumentation ----------------------------------------------------------------------------- Bitte besuchen Sie die vollständige Dokumentation auf unserer Webseite. Hier sind ein paar Wege zum Anfangen. * Komplette Dokumentation finden sie online: => http://wrapper.tanukisoftware.com/doc/german/ * Wie Sie Ihrer Anwendung mit dem Java Service Wrapper integrieren => http://wrapper.tanukisoftware.com/doc/german/integrate.html * Konfigurationseigenschaften => http://wrapper.tanukisoftware.com/doc/german/properties.html * HOWTOs => http://wrapper.tanukisoftware.com/doc/german/howto.html * Javadocs, für fortgeschrittene Benutzer => http://wrapper.tanukisoftware.com/doc/german/javadocs.html * Tanuki Software, Ltd. Firmenseite: => http://www.tanukisoftware.com/ 3. Installation ----------------------------------------------------------------------------- Wenn Sie das hier lesen, heißt das, dass Sie bereits unsere Software entpackt haben. Die Standard und Professional Editionen des Java Service Wrappers beinhalten bereits eine zeitlich beschränkte aber vollfunktionstüchtige Triallizenz, die es Ihnen erlaubt den Wrapper unbegrenzt oft zu starten und jeweils für 15 Minuten zu laufen. Dies ist für einfache, ungezwungene erste Tests gedacht. Sie können ebenfalls kostenlos eine 1monatige Triallizenz beantragen, die wie eine Serverlizenz funktioniert und auf einem Server Ihrer Wahl verwendet werden kann. Triallizenzen können auf folgender Seite beantragt werden: => http://wrapper.tanukisoftware.com/doc/german/requestTrial.jsp Dauerhafte Lizenzen können desweiteren auf der folgenden Seite erworben werden: => http://wrapper.tanukisoftware.com/doc/german/accountLicenses.jsp The Community Edition benötigt keinerlei Lizenz! Sollten Sie bereits eine Lizenz erworben haben, können Sie den Lizenzschlüssel auf der folgendenen Seiten erstellen und herunterladen: Für Serverlizenzen: => http://wrapper.tanukisoftware.com/doc/german/accountServerLicenses.jsp Für Entwicklerlizenzen: => http://wrapper.tanukisoftware.com/doc/german/accountDevLicenses.jsp Abhängig von der Art der Javaanwendung, bedarf es verschiedene Arten, wie Sie die Anwendung mit dem Wrapper zu integrieren. Die Integrationsschritte finden Sie auf folgender Seite: => http://wrapper.tanukisoftware.com/doc/german/integrate.html 4. Lizenzoptionen ----------------------------------------------------------------------------- Der Java Service Wrapper ist verfügbar unter 3 verschiedenen Lizenzen: * Entwicklerlizenz Vereinbarung (Kommerziell) * Serverlizenz Vereinbarung (Kommerziell) * Communitylizenz Vereinbarung (GPL2) Für mehr Informationen besuchen Sie bitte die Lizenzübersicht auf unserer Seite: => http://wrapper.tanukisoftware.com/doc/german/licenseOverview.html 5. Wie zu erwerben? ----------------------------------------------------------------------------- Sollten Sie interessiert sein and den Features der Standard bzw. Professional Edition, so können Sie diese hier online erwerben: => http://wrapper.tanukisoftware.com/doc/german/accountLicenses.jsp 6. Aktualisieren ----------------------------------------------------------------------------- Sie finden die aktuellste version des Wrappers auf unserer Downloadseite: => http://wrapper.tanukisoftware.com/doc/german/download.jsp Für die Anleitung gehen Sie bitte auf diese Seite: => http://wrapper.tanukisoftware.com/doc/german/howto-upgrade.html 7. FAQ ----------------------------------------------------------------------------- Bitte gehen Sie auf den FAQ-bereich unserer Seite: => http://wrapper.tanukisoftware.com/doc/german/faq.html Desweiteren haben wir auch eine Troubleshooting, HOWTOs und Fragen & Antwortenseite: => http://wrapper.tanukisoftware.com/doc/german/troubleshooting.html => http://wrapper.tanukisoftware.com/doc/german/howto.html => http://wrapper.tanukisoftware.com/doc/german/qna.html 8. Support ----------------------------------------------------------------------------- Bitte gehen Sie auf unsere Supportseite: => http://wrapper.tanukisoftware.com/doc/german/support.jsp 9. Systemvoraussetzungen ----------------------------------------------------------------------------- Eine vollständige Liste der unterstützten Plattformen und Systemvoraussetzungen können Sie auf der folgenden Seite finden: => http://wrapper.tanukisoftware.com/doc/german/supported-platforms.html ----------------------------------------------------------------------------- Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved. wrapper_3.5.26_src/README_en.txt100644 0 0 12773 12440202301 13545 0ustar 0 0 ----------------------------------------------------------------------------- Java Service Wrapper Community Edition 3.5.26 Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved. http://wrapper.tanukisoftware.com ----------------------------------------------------------------------------- Summary: 1. What is the Java Service Wrapper? 2. Documentation 3. Installation 4. License Options 5. How to buy 6. Getting Updates 7. FAQ 8. Support 9. System Requirements 1. What is the Java Service Wrapper? ----------------------------------------------------------------------------- The Java Service Wrapper is an application which has evolved out of a desire to solve a number of problems common to many Java applications. Some of the Wrapper's features are: * Run a Java application as a Windows Service or Unix Daemon * Java Application Reliability * Automatic Crash, Freeze, and Deadlock Detection and Recovery * On Demand Restarts * Standard, Out of the Box Scripting * Flexible Cross Platform Configuration * Ease Application Installations * Logging * Many more... See our download page for a more detailed feature list. => http://wrapper.tanukisoftware.com/doc/english/download.jsp For more information please visit => http://wrapper.tanukisoftware.com/doc/english/introduction.html 2. Documentation ----------------------------------------------------------------------------- Please visit our website for full documentation. Here are some ways to get you started. * Complete documentation can be found online: => http://wrapper.tanukisoftware.com/ * How to integrate the Java Service Wrapper with an Application => http://wrapper.tanukisoftware.com/doc/english/integrate.html * Configuration Properties => http://wrapper.tanukisoftware.com/doc/english/properties.html * HOWTOs => http://wrapper.tanukisoftware.com/doc/english/howto.html * Javadocs, for advanced users => http://wrapper.tanukisoftware.com/doc/english/javadocs.html * Tanuki Software, Ltd. Corporate site: => http://www.tanukisoftware.com/ 3. Installation ----------------------------------------------------------------------------- If you are reading this it means you successfully unpacked this software. The Standard and Professional Editions of the Java Service Wrapper ship with a time limited, but full featured, trial license key which allows you to run the Wrapper as many times as you want for up to 15 minutes. This is meant for quick no hassle testing. You can also request a FREE 1 month trial license which allows you to run the Wrapper for a full month on a single server. Trial licenes can be obtained at the following URL: => http://wrapper.tanukisoftware.com/doc/english/requestTrial.jsp Permantent licenses can also be purchased at the following URL: => http://wrapper.tanukisoftware.com/doc/english/accountLicenses.jsp The Community Edition does not require a license key. If you have already purchased a license, you can generate and download your license key by logging on and viewing your License Management Page. For Server Licenses: => http://wrapper.tanukisoftware.com/doc/english/accountServerLicenses.jsp For Development Licenses: => http://wrapper.tanukisoftware.com/doc/english/accountDevLicenses.jsp Depending on the specific type of Java application that will be run with the Wrapper, there are a few integration options available: => http://wrapper.tanukisoftware.com/doc/english/integrate.html 4. License Options ----------------------------------------------------------------------------- The Java Service Wrapper is made available in under three licenses. * Development License Agreement (Commercial) * Server License Agreement (Commercial) * Community License Agreement (GPL2) For more information, please browse our license overview: => http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html 5. How to buy ----------------------------------------------------------------------------- If you are interested in the features available with our Standard or Professional Editions, licenses can be purchased online: => http://wrapper.tanukisoftware.com/doc/english/accountLicenses.jsp 6. Getting Updates ----------------------------------------------------------------------------- You can always find the latest Wrapper release on our download page: => http://wrapper.tanukisoftware.com/doc/english/download.jsp We also offer an upgrade guide: => http://wrapper.tanukisoftware.com/doc/english/howto-upgrade.html 7. FAQ ----------------------------------------------------------------------------- Please see our general FAQ page: => http://wrapper.tanukisoftware.com/doc/english/faq.html We also offer Troubleshooting, HOWTOs, and a Question & Answers page: => http://wrapper.tanukisoftware.com/doc/english/troubleshooting.html => http://wrapper.tanukisoftware.com/doc/english/howto.html => http://wrapper.tanukisoftware.com/doc/english/qna.html 8. Support ----------------------------------------------------------------------------- Please see the following page for support options: => http://wrapper.tanukisoftware.com/doc/english/support.jsp 9. System Requirements ----------------------------------------------------------------------------- A full list of supported platforms and system requirements can be found online: => http://wrapper.tanukisoftware.com/doc/english/supported-platforms.html ----------------------------------------------------------------------------- Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved. wrapper_3.5.26_src/README_es.txt100644 0 0 15413 12440202301 13544 0ustar 0 0 ----------------------------------------------------------------------------- Java Service Wrapper Community Edition 3.5.26 Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved. http://wrapper.tanukisoftware.com ----------------------------------------------------------------------------- Resumen: 1. ¿Qué es el Java Service Wrapper? 2. Documentación 3. Instalación 4. Tipos de Licencia 5. ¿Cómo comprar? 6. Actualizaciones 7. FAQ 8. Soport Técnico 9. Requisitos del Sistema 1. ¿Qué es el Java Service Wrapper? ----------------------------------------------------------------------------- El Java Service Wrapper es una aplicación que ha evolucionado con el deseo de resolver una seria de problemas comúnes encontrados en aplicaciones Java. Alguna de nuestras características son: * Correr aplicaciones Java como Servicio de Windows o Demonio de Unix * Fiabilidad en Aplicaciones Java * Detección y recuperación automática cuando se presenta un tipo de Crash, congelamiento o bloqueo (Deadlock) * Reinicios de la JVM en demanda * Scripts listos para implementar una forma de instalación estándar. * Configuración flexible en varias plataformas * Instalaciones más fáciles * Y muchas más... Por favor visite nuestra página de Descargas para una lista más detallada. => http://wrapper.tanukisoftware.com/doc/english/download.jsp (Sólo Inglés) Para más información por favor visite => http://wrapper.tanukisoftware.com/doc/english/introduction.html (Sólo Inglés) 2. Documentación ----------------------------------------------------------------------------- Por favor visite nuestro sitio web para ver toda nuestra documentación. Aquí hay algunas maneras de empezar. * La documentación completa puede ser encontrada en línea en: => http://wrapper.tanukisoftware.com/ (Sólo Inglés) * ¿Cómo integrar el Java Service Wrapper con mi aplicación? => http://wrapper.tanukisoftware.com/doc/english/integrate.html (Sólo Inglés) * Configuración de Propiedades => http://wrapper.tanukisoftware.com/doc/english/properties.html (Sólo Inglés) * HOWTOs => http://wrapper.tanukisoftware.com/doc/english/howto.html (Sólo Inglés) * Javadocs, para usuarios avanzados => http://wrapper.tanukisoftware.com/doc/english/javadocs.html (Sólo Inglés) * Sitio de la compañia - Tanuki Software, Ltd.: => http://www.tanukisoftware.com/ 3. Instalación ----------------------------------------------------------------------------- Si usted está leyendo esto, quiere decir que ha podido desempacar exitosamente nuestro software. Las ediciones estándar y profesionales del Java Service Wrapper son distribuidas con una licencia de prueba limitada, con todas las características habilitadas pero sólo cuenta con una duración de 15 minutos. Usted puede ejectuar nuestro software tantas veces quiera, esto le ofrece una manera rápida y sencilla de probar el Java Service Wrapper. Usted tambien puede adquirir una licencia gratuita de prueba válida por un mes. Esta licencia le permite ejecturar nuestro programa en un servidor, sin ningún límite de tiempo de ejecución y con todas las características habilitadas. La licencia de prueba puede ser adquirida en: => http://wrapper.tanukisoftware.com/doc/english/requestTrial.jsp (Sólo Inglés) Para adquirir una licencia permanente, usted la puede comprar en: => http://wrapper.tanukisoftware.com/doc/english/accountLicenses.jsp (Sólo Inglés) La edición para la comunidad (Community Edition) no require una licencia. Si usted ya compró una licencia, por favor genere su licencia en nuestro sitio web, para esto usted necesita entrar los datos de su cuenta con la que adquirio el producto. Para administrar licencias tipo servidor (Server), por favor visite: => http://wrapper.tanukisoftware.com/doc/english/accountServerLicenses.jsp (Sólo Inglés) Para administrar licencias tipo desarrollo (Development), por favor visite: => http://wrapper.tanukisoftware.com/doc/english/accountDevLicenses.jsp (Sólo Inglés) Como cada aplicación Java es diferente, nosotros ofrecemos varios tipos de integración, por favor visite: => http://wrapper.tanukisoftware.com/doc/english/integrate.html (Sólo Inglés) 4. Tipos de Licencia ----------------------------------------------------------------------------- El Java Service Wrapper está disponible bajo tres licencias. * Licencia de Desarrollo (Comercial) (Development License) * Licencia para Servidores (Comercial) (Server License) * Licencia para la Comunidad (GPL2) (Community License) Para más información, por favor visite nuestra página de licencias en: => http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html (Sólo Inglés) 5. ¿Cómo comprar? ----------------------------------------------------------------------------- Si está interesado en características solo disponibles para nuestras ediciones Estándar y Profesional, usted necesita comprar una licencia. Usted puede comprarlas en línea visitando: => http://wrapper.tanukisoftware.com/doc/english/accountLicenses.jsp (Sólo Inglés) 6. Actualizaciones ----------------------------------------------------------------------------- Usted siempre puede encontrar la versión más reciente en: => http://wrapper.tanukisoftware.com/doc/english/download.jsp (Sólo Inglés) Nosotros también ofrecemos una guía para actualizar nuestro software en: => http://wrapper.tanukisoftware.com/doc/english/howto-upgrade.html (Sólo Inglés) 7. FAQ ----------------------------------------------------------------------------- Para ver nuestro FAQ general, por favor visite: => http://wrapper.tanukisoftware.com/doc/english/faq.html (Sólo Inglés) Solución de problems, HOWTOs o nuestra sección de Preguntas y Respuestas => http://wrapper.tanukisoftware.com/doc/english/troubleshooting.html => http://wrapper.tanukisoftware.com/doc/english/howto.html => http://wrapper.tanukisoftware.com/doc/english/qna.html (Sólo Inglés) 8. Soporte Técnico ----------------------------------------------------------------------------- Por favor visite nuestra página de soporte para más opciones. Usted puede ver las opciones disponibles en: => http://wrapper.tanukisoftware.com/doc/english/support.jsp (Sólo Inglés) 9. Requisitos del Sistema ----------------------------------------------------------------------------- La lista completa de plataformas soportadas y requisitos necesarios puede ser encontrada en: => http://wrapper.tanukisoftware.com/doc/english/supported-platforms.html (Sólo Inglés) ----------------------------------------------------------------------------- Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved. wrapper_3.5.26_src/README_ja.txt100644 0 0 17015 12440202301 13527 0ustar 0 0 ----------------------------------------------------------------------------- Java Service Wrapper Community Edition 3.5.26 Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved. http://wrapper.tanukisoftware.com ----------------------------------------------------------------------------- 概要: 1. Java Service Wrapperとは? 2. ドキュメンテーション 3. インストール 4. ライセンスの種類 5. ライセンス購入方法 6. アップデート方法 7. よくある質問FAQ 8. サポート 9. システム要件 1. Java Service Wrapperとは? ----------------------------------------------------------------------------- Java Service Wrapperは、多くのJavaアプリケーションによくある問題を解決したい という多くの要望に応えて登場したアプリケーションです。 主なWrapperの特徴: * WindowsサービスやUnixデーモンとしてJavaアプリケーションを動かす * 信頼性のあるJavaアプリケーション * クラッシュ、フリーズ、デッドロックなど自動検知および自動リカバリー * オン・デマンドによる再起動 * 簡単にすぐ使えるスクリプトつき * クロスプラットフォームに対応した柔軟なコンフィギュレーション * アプリケーションの簡単インストール * ログ * もっと詳しく... さらに詳しい特徴などはダウンロード・ページをご覧ください。 => http://wrapper.tanukisoftware.com/doc/japanese/download.jsp さらに詳しくはこちらもご覧ください。 => http://wrapper.tanukisoftware.com/doc/japanese/introduction.html 2. ドキュメンテーション ----------------------------------------------------------------------------- 完全なドキュメンテーションをご覧になりたい場合にはウェブサイトをご覧ください。 「始めるには?」を簡単にご紹介します。 * オンラインで完全なドキュメンテーションをご覧になれます: => http://wrapper.tanukisoftware.com/doc/japanese/ * JavaアプリケーションをJava Service Wrapperとインテグレーションする方法: => http://wrapper.tanukisoftware.com/doc/japanese/integrate.html * コンフィギュレーション・プロパティ一覧: => http://wrapper.tanukisoftware.com/doc/japanese/properties.html * HOWTO(ハウツー): => http://wrapper.tanukisoftware.com/doc/japanese/howto.html * Javadocs(上級レベルのユーザー向け): => http://wrapper.tanukisoftware.com/doc/japanese/javadocs.html * タヌキソフトウェア有限会社サイト: => http://www.tanukisoftware.com/ja/ 3. インストール ----------------------------------------------------------------------------- これを読む前にソフトウェアをダウンロードで入手して解凍してスタンバイください。 Java Service Wrapperのスタンダード版やプロフェッショナル版には、時間制限つきの トライアル・ライセンスを同梱してあり、全ての機能を利用できます。 このライセンスキーでは1回の稼働が最長15分までに制限されていますが、 回数に関係なく何度でも利用が可能です。簡単にクイックテストなど便利に使えます。 さらに長時間の利用を希望であれば、1台のサーバー上で使える1カ月の無料トライアル ライセンスもご用意しています。 1カ月トライアル・ライセンスは次のページからリクエストすることができます: => http://wrapper.tanukisoftware.com/doc/japanese/requestTrial.jsp 永久ライセンスを購入されるには: => http://wrapper.tanukisoftware.com/doc/japanese/accountLicenses.jsp Java Service Wrapperコミュニティー版にはライセンスキーは不要です。 既にライセンスを購入済みの方は、サイトにログインして、ライセンス管理ページで ライセンスキーを生成することができます。 ライセンス管理(サーバーライセンス)ページ: => http://wrapper.tanukisoftware.com/doc/japanese/accountServerLicenses.jsp ライセンス管理(開発ライセンス)ページ: => http://wrapper.tanukisoftware.com/doc/japanese/accountDevLicenses.jsp Java Service Wrapperで動かすJavaアプリケーションの種類により、 いくつかインテグレーション方法があります: => http://wrapper.tanukisoftware.com/doc/japanese/integrate.html 4. ライセンスの種類 ----------------------------------------------------------------------------- Java Service Wrapperの利用には3つのライセンスがあります。 * 開発ライセンス契約 (商用ライセンス) * サーバーライセンス契約 (商用ライセンス) * コミュニティーライセンス契約 (GPL2ライセンス) さらに詳しくは、ライセンス概要をご覧ください: => http://wrapper.tanukisoftware.com/doc/japanese/licenseOverview.html 5. ライセンス購入方法 ----------------------------------------------------------------------------- Java Service Wrapperスタンダード版あるいはプロフェッショナル版の機能を ご利用になるには、オンラインでライセンスを購入することが可能です。 => http://wrapper.tanukisoftware.com/doc/japanese/accountLicenses.jsp 銀行振り込みを希望される場合は sales@tanukisoftware までお問い合わせ願います。 銀行情報をご連絡いたします。 代理店、ディストリビューター経由からの購入も可能です。   => http://www.tanukisoftware.com/ja/distributors.php 6. アップデート方法 ----------------------------------------------------------------------------- 最新のJava Service Wrapperリリースはいつでもダウンロード・ページで入手できます: => http://wrapper.tanukisoftware.com/doc/japanese/download.jsp 最新版へのアップデート手順ガイド: => http://wrapper.tanukisoftware.com/doc/japanese/howto-upgrade.html 7. よくある質問FAQ ----------------------------------------------------------------------------- よくある質問FAQページも便利に活用いただけることと思います: => http://wrapper.tanukisoftware.com/doc/japanese/faq.html その他、トラブルシューティング、HOWTO, 質問と回答など各ページもご活用ください: => http://wrapper.tanukisoftware.com/doc/japanese/troubleshooting.html => http://wrapper.tanukisoftware.com/doc/japanese/howto.html => http://wrapper.tanukisoftware.com/doc/japanese/qna.html 8. サポート ----------------------------------------------------------------------------- 皆様が快適にユーザーサポートを受けられるよう、いくつかオプションをご用意して います。サポートの詳細については弊社のサポートページをご覧ください: => http://wrapper.tanukisoftware.com/doc/japanese/support.jsp 9. システム要件 ----------------------------------------------------------------------------- サポートされているプラットフォームやシステム要件など完全なリストを オンラインでご用意していますのでご参照ください: => http://wrapper.tanukisoftware.com/doc/japanese/supported-platforms.html ----------------------------------------------------------------------------- Copyright (C) 1999-2014 Tanuki Software, Ltd. All Rights Reserved. wrapper_3.5.26_src/build-tests.xml100644 0 0 376467 12440202301 14403 0ustar 0 0 wrapper.java.classpath.1=../lib/wrapper.jar wrapper.console.format=PM wrapper.console.format=PM wrapper.console.format=PM ]]> wrapper.java.additional.1= wrapper.java.additional.1=-verbose:gc wrapper.java.additional.1= ]]> wrapper.syslog.loglevel=NONE wrapper.syslog.loglevel=NONE wrapper.java.additional.1= wrapper.java.classpath.2=../lib/wrapper.jar wrapper.java.classpath.2=../lib/wrapper.jar wrapper.java.classpath.2=../lib/wrapper.jar wrapper.java.classpath.2=../lib/wrapper.jar wrapper.syslog.loglevel=NONE wrapper.syslog.loglevel=NONE wrapper.java.additional.1= wrapper.java.classpath.1=../lib/wrapper.jar wrapper.java.classpath.1=../lib/wrapper.jar wrapper.java.classpath.1=../lib/wrapper.jar ]]> ]]> ]]> ABC DEF GHI ]]> "Hello World." ]]> "Hello World." ]]> #encoding=UTF-8 ABC ]]> # This is a comment. ABC # This is another comment. DEF##param2 "#GHI" ]]> %WRAPPER_LANG% "%WRAPPER_BIN_DIR%" %WRAPPER_BITS% -Dparam1=param1 -Dparam2=param2 -Dparam3=param3 -Dparam="Hello World." -Dparam="Hello World." #encoding=UTF-8 -Dparam=param # This is a comment. -Dparam1=param1 # This is another comment. -Dparam2=##param2 -Dparam3="#param3" -Dparam1=%WRAPPER_LANG% -Dparam2="%WRAPPER_BIN_DIR%" -Dparam3=%WRAPPER_BITS% wrapper.java.additional.1= wrapper.java.additional.1= wrapper.java.additional.1= setlocal the needs of your application wrapper_3.5.26_src/build.xml100644 0 0 330721 12440202301 13222 0ustar 0 0 wrapper.check.deadlock.interval=60 wrapper.java.classpath.1=../lib/wrapper.jar # Wrapper Properties wrapper.java.classpath.1=../lib/wrapper.jar # Out Of Memory detection. ********************************************************** * Pre-release distributions can only be generated using * * Java 1.4 JVMs to guarantee that the resulting jars * * will run on all platforms. * * This is a ${java.specification.version} JVM. * ********************************************************** <html><body> The javadocs for this application are found in $WRAPPER_HOME/jdoc.tar.gz. Please extract this archive into the $WRAPPER_HOME directory.<p>The javadocs could not be included directly in the original tar distribution due to a lack of support for long path names in some tar implementations. </body></html> ********************************************************** * An intermediate pre-release distribution has been * * created in the dist directory. This file can be * * expanded on any system to quickly produce a native * * release by running "build<64/32> release". * * * * Alternately a release can be generated for the current * * platform by running "build<64/32> release" now. * * * * Intermediate pre-release distributions: * * ${dist.dir}/${intermfile}.zip * ${dist.dir}/${intermfile}.tar.gz ********************************************************** ********************************************************** * You must first either run the pre-release task in a * * full source distribution or run within an intermediate * * pre-release distribution. * ********************************************************** ERROR: ************************************************************************** * The password for the CodeSigning Certificate is not set. * Please define it on the commandline: ant -Dwrapper.cert.password="..." ************************************************************************** ERROR: **************************************************************************** * Please specify the path for SignTool in default.properties (signtool.dir). **************************************************************************** ERROR: ************************************************************************************************************ * The directory specified in signtool.dir (${signtool.dir}) does not exist/or does not contain signtool.exe. * Please verify the folder contains the file!! ************************************************************************************************************ ERROR: **************************************************************************** * Please specify the path to the certificate in default.properties (cert.dir). **************************************************************************** ERROR: ************************************************************************************************************ * The directory specified in cert.dir (${cert.dir}) does not exist/or does not contain the certificate codesigncert.pfx. * Please verify the folder contains the file!! ************************************************************************************************************ # Wrapper Properties wrapper.java.classpath.1=../lib/wrapper.jar # Out Of Memory detection. ********************************************************** * A native release distribution has been created in the * * dist directory. * * * * Release distribution: * * ${dist.dir}/${releasefile}.zip ********************************************************** # Wrapper Properties wrapper.java.classpath.1=../lib/wrapper.jar # Out Of Memory detection. <html><body> The javadocs for this application are found in $WRAPPER_HOME/jdoc.tar.gz. Please extract this archive into the $WRAPPER_HOME directory.<p>The javadocs could not be included directly in the original tar distribution due to a lack of support for long path names in some tar implementations. </body></html> ********************************************************** * A native release distribution has been created in the * * dist directory. * * * * Release distribution: * * ${dist.dir}/${releasefile}.tar.gz ********************************************************** wrapper.check.deadlock.interval=60 wrapper.java.classpath.1=../lib/wrapper.jar # Wrapper Properties wrapper.java.classpath.1=../lib/wrapper.jar <html><body> The javadocs for this application are found in $WRAPPER_HOME/jdoc.tar.gz. Please extract this archive into the $WRAPPER_HOME directory.<p>The javadocs could not be included directly in the original tar distribution due to a lack of support for long path names in some tar implementations. </body></html> ********************************************************** * A delta-pack release distribution has been created in * * the dist directory. * * * * Release distributions: * * ${dist.dir}/${deltareleasefile}.zip * ${dist.dir}/${deltareleasefile}.tar.gz ********************************************************** wrapper_3.5.26_src/build32.bat100644 0 0 366 12440202300 13253 0ustar 0 0 @echo off setlocal set BUILDFILE=%~dp0%build.xml echo -------------------- echo Wrapper Build System echo using %BUILDFILE% echo -------------------- call "%ANT_HOME%\bin\ant.bat" -f "%BUILDFILE%" -Dbits=32 %1 %2 %3 %4 %5 %6 %7 %8 wrapper_3.5.26_src/build64.bat100644 0 0 363 12440202300 13255 0ustar 0 0 @echo off setlocal set BUILDFILE=%~dp0%build.xml echo -------------------- echo Wrapper Build System echo using %BUILDFILE% echo -------------------- call "%ANT_HOME%\bin\ant.bat" -f "%BUILDFILE%" -Dbits=64 %1 %2 %3 %4 %5 %6 %7 %8 wrapper_3.5.26_src/default.properties100644 0 0 6616 12440202301 15106 0ustar 0 0 # ------------------------------------------------------------------- # B U I L D P R O P E R T I E S # ------------------------------------------------------------------- # Specifies default property values # Overridden ant.properties # Not user-editable; use ant.properties files instead name = wrapper Name = Wrapper long.name = Java Service Wrapper Community ${Version} Version = 3.5.26 version = ${Version} version.root = 3.5.26 year = 2014 # NOTE - The version property gets corrupted by the use of Xalan # so Version is used instead. app.name = testwrapper app.caps.name = TestWrapper app.long.name = Test Wrapper Sample Application app.desc = Test Wrapper Sample Application Description # Settings used to configure compile environment build.debug = on build.optimize = off build.deprecation = off build.compress = false junit.failonerror = true # location of intermediate products build.dir = ${basedir}/build build.classes = ${build.dir}/classes build.testclasses = ${build.dir}/testclasses build.tests = ${build.dir}/tests dist.dir = ${basedir}/dist signtool.dir=C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0\\Bin cert.dir= # Set the properties for existing directories bin.dir = ${basedir}/bin conf.dir = ${basedir}/conf src.dir = ${basedir}/src lib.dir = ${basedir}/lib logs.dir = ${basedir}/logs doc.dir = ${basedir}/doc jdoc.dir = ${basedir}/jdoc test.dir = ${basedir}/test context.dir = ${src.dir}/documentation tools.dir = ${basedir}/tools # -------------------------------------------------- # REQUIRED LIBRARIES # -------------------------------------------------- # List of possible locations for the visual studio setup scripts vcvars.v8_32_1=c:\\Program Files\\Microsoft Visual Studio 10.0\\VC\\bin\\vcvars32.bat vcvars.v8_32_2=d:\\Program Files\\Microsoft Visual Studio 10.0\\VC\\bin\\vcvars32.bat vcvars.v8_32_3=c:\\Program Files\\Microsoft Visual Studio 9.0\\VC\\bin\\vcvars32.bat vcvars.v8_32_4=d:\\Program Files\\Microsoft Visual Studio 9.0\\VC\\bin\\vcvars32.bat vcvars.v8_32_5=c:\\Program Files\\Microsoft Visual Studio 8\\VC\\bin\\vcvars32.bat vcvars.v8_32_6=d:\\Program Files\\Microsoft Visual Studio 8\\VC\\bin\\vcvars32.bat vcvars.v8_32_7=C:\\Program Files\\Microsoft Platform SDK for Windows Server 2003 R2\\SetEnv.Cmd vcvars.v8_32_7.arg.1=/XP32 vcvars.v8_32_7.arg.2=/RETAIL vcvars.v8_32_8=C:\\Program Files\\Microsoft Platform SDK\\SetEnv.Cmd vcvars.v8_32_8.arg.1=/XP32 vcvars.v8_32_8.arg.2=/RETAIL vcvars.v8_x86_64_1=c:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\bin\\vcvars64.bat vcvars.v8_x86_64_2=c:\\Program Files\\Microsoft Visual Studio 9\\VC\\bin\\amd64\\vcvarsamd64.bat vcvars.v8_x86_64_3=c:\\Program Files\\Microsoft Platform SDK for Windows Server 2003 R2\\SetEnv.Cmd vcvars.v8_x86_64_3.arg.1=/XP64 vcvars.v8_x86_64_3.arg.2=/RETAIL vcvars.v8_x86_64_4=c:\\Program Files\\Microsoft Platform SDK\\SetEnv.Cmd vcvars.v8_x86_64_4.arg.1=/XP64 vcvars.v8_x86_64_4.arg.2=/RETAIL vcvars.v8_x86_64_5=C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Bin\\SetEnv.cmd vcvars.v8_x86_64_5.arg.1=/x64 vcvars.v8_x86_64_6=c:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\bin\\x86_amd64\\vcvarsx86_amd64.bat vcvars.v8_ia_64_1=c:\\Program Files\\Microsoft Platform SDK\\SetEnv.Cmd vcvars.v8_ia_64_1.arg.1=/SRV64 vcvars.v8_ia_64_1.arg.2=/RETAIL # -------------------------------------------------- # OPTIONAL LIBRARIES # -------------------------------------------------- wrapper_3.5.26_src/doc/index.html100644 0 0 703 12440202301 14055 0ustar 0 0 Java Service Wrapper Documentation Complete documentation can be found online:
http://wrapper.tanukisoftware.org

Java docs are available online as well:
http://wrapper.tanukisoftware.org/jdoc/index.html wrapper_3.5.26_src/doc/revisions.txt100644 0 0 664404 12440202301 14740 0ustar 0 0 Java Service Wrapper Revision History. -------------------------------------- 3.5.26 * Improve the log messages when a JVM restart is requested when the Wrapper is in a state that it will be ignored. * (Standard, Professional) Add an additional debug message when a deadlock sweep completes. No functional change but this was added to make it easy to tell how long the sweep takes on a given application. * Clean up the internal tracking of where environment variables were set. No functional changes. * When detecting Cygwin with 'uname -o' in the script file, some OS's (Solaris, MacOS, etc.) show an error message because '-o' is not a valid parameter. Now we hide this error message to avoid confusion and we can guess that Cygwin is not running. * Allow to control the service in systemd using the script file. * Improve script file. Fix a typo. On MacOS, add another alternative way to find Java and use full path to execute sysctl in case it's not in the path. Thanks to Dannes Wessels for pointing this out. * Fix a problem on newer version of Windows when customizing the Wrapper. The certificate was not removed when creating the target. This was leading to an error when trying to sign the target with a new certificate. * Add missing support in the shell script for restarting/stopping the Wrapper service with launchctl on Mac OS X. * Add missing support in the shell script for restarting/stopping the Wrapper service with Upstart. * Add the ability to set the path of the 'su' command as well as the ability to specifiy additional options in the Wrapper shell script using new SU_BIN and SU_OPTS variables. * Fix a problem in the WrapperSimpleApp, WrapperStartStopApp, and WrapperJarApp helper classes where command line problems that resulted in the JVM exiting on startup looked like unexpected exits. This meant that the Wrapper would try to relaunch the JVM again rather than giving up on the first attempt. * Modified the WrapperSimpleApp, WrapperStartStopApp, and WrapperJarApp helper classes so that their usage banners will only now be shown for command line related problems. Issues with the specified classes, methods, or jar files are still logged as errors, but showing the user the usage in these cases was confusing. * Correct the WrapperResources.getString() method that has no replacement arguments so that its processing of the raw string is handled the same as methods which have replacement arguments. Now all strings are processed by the MessageFormat class before being returned. Previous versions were not consistent about the need to escape single quotes. * Added optional key validation to make sure that strings passed in to the WrapperResources.getString() method are formatted correctly. See the WrapperResources class for information how to enable. * Clean up escaping of single quotes in a few messages. * Add new options for property wrapper.backend.type: AUTO, SOCKET, SOCKET_IPv4, SOCKET_IPv6, PIPE. When set to AUTO, the Wrapper will try to open a socket ipv4 and fallback to ipv6 and to pipe in case of error. * Fix bug when converting from multibyte to wide char without setting the locale at startup (Unix only). Thanks to Bert. * Add a 'CLOSE_BACKEND' alias to 'CLOSE_SOCKET' as a test command for the wrapper.commandfile property. This is because there have been multiple options for the backend connection for some time and the name is more portable. * Fix a problem on Mac when running OS X Yosemite where the script was failing to correctly compare versions '10.10' to '10.5.0'. This was leading to the script thinking that only 32-bit binaries could be run. This was only an issue if the delta pack naming of the wrapper binaries was being used. * Add a new wrapper.java.classpath.missing.loglevel property which makes it possible to control how the Wrapper logs warnings about missing classpath elements. Previously this was always logged as debug output and could not be disabled. * If there are any low level problems launching the Java process that are not related to configuration or the JVM itself, the Wrapper will no longer try again as such retries were meaningless. * Windows system APIs have a problem that cause a process to crash if it attempts to set an environment variable over 32767 characters in length. The Wrapper now checks for this and logs an error rather than setting the variable. This was a problem if very large classpaths were used when the wrapper.java.classpath.use_environment property was TRUE. * Windows does not allow a command line to be longer than 32766 characters in length. Different versions of Windows handle it differently when such a long command is provided. The Wrapper now does its own check and shows an error in a consistent way. * Improve the error message on UNIX platforms when the command line is longer than the system maximum. This maximum varies greatly by platform and environment and is difficult to calculate reliably, so the maximum length is not currently shown in the message. * Fix a problem on UNIX platforms where a very large configuration file could cause the WrapperManager to fail to startup. This was caused by the partial transfer of the configuration file to the WrapperManager via the backend connection. This would happen regardless of the backend type used. The size of the configuration file that would cause a problem varied greatly based on the specific system. * Fix a problem on Windows platforms where a very large configuration file would fail to be sent to the WrapperManager on startup when the wrapper.backend.type property was set to PIPE. The only problem was that the WrapperManager.getProperties() method would be empty. * (Professional) Add checks to the WrapperManager.exec() methods on Windows for the maximum command line length of 32766, and maximum environment variable name-value pair length of 32767. * (Professional) Fix a problem where a free of a NULL pointer was being done as part of the cleanup process of a WrapperManager.exec() call. This is not known to have caused any issues. * Added getStdOut(), getStdErr(), and getStdIn() methods to the WrapperProcess class as aliases to the getInputStream(), getErrorStream(), and getOutputStream() methods to help avoid confusion. * Fix a problem on Windows 7 where long log lines got corrupted after 31397 characters when wrapper.console.direct was true. This seems to be a problem with the underlying Windows API and was only a display issue. Reduced the maximum number of characters that can be written with a single API call to 30000 to work around the issue. This change is internal and there is still no limit on the length of logged lines. * Fix a deadlock if the Wrapper failed to write to the backend when the wrapper.backend.type property was PIPE. Found by code review and is not known to have actually happened. * From Mac OSX 10.5.0, the script file will use the key 'KeepAlive' in the launchctl configuration file. Prior versions of Mac OSX will continue to use the same key 'OnDemand'. Thanks to Robin for pointing this out. * (Standard, Professional) Disallow the use of hostids tied to Apple Bluetooth devices when running on a virtualized Windows system hosted on an OS X system. * Fix a problem where WrapperManager.log() was not working correctly when multi-byte messages were logged. * In the debug output the full configuration properties packet is suppressed from the log output because it is huge and can contain sensitive data. Add a size to the abbreviated output to assist with debugging. * Fix a memory leak on UNIX platforms whenever an error message was reported. This was only a problem if the message was logged repeatedly. * Correct a couple other potential memory leaks found through code review. Not known to have been causing any actual problems. 3.5.25 * (Professional) Improve the wrapper.timer..interval property so it is now possible to specify ranges and lists of values as well as offsets for interval values to more precisely control when timers are fired. * (Professional) Fix a problem with the wrapper.timer..interval property where timers would not fire during an interval the system time was set back. Also fixed a problem where timers would stop firing permanently if the system time was set forward by more than the value of the wrapper.timer.max_catchup property and a timer had been scheduled to be fired during that interval. Both of these issues were most likely during daylight savings time. * Fix a problem where signals received by the JVM were not being logged in debug output correctly if the wrapper.ignore_signals property is set to true. We now also log debug output even if a user event listener consumes the signal event. * Fix a problem on Gentoo Linux where the shell script was not correctly detecting the system architecture. This may also be a problem on other distributions whose 'uname -p' returns a detailed architecture. * In the shell script, when the flag to use systemd (USE_SYSTEMD) is set, the shell script generates a ".service" file in /etc/systemd/system/ when installing the Wrapper as a daemon. * In the shell script, add a function to validate the size of APP_NAME when installing or removing the daemon on AIX. * It was possible to disable the logging of the Java command line even when debug output was enabled by setting the wrapper.java.command.loglevel property to NONE. This made it difficult to debug problems and is no longer possible. * When the wrapper.java.version.output property is set to true, add debug log output to show the actual command line used. * Fix a problem on Windows when the wrapper.java.version.output property is true where it was possible that java executable being run to get the version could be different than that used to run the application if the java executable was being located on the default system PATH as well as the PATH defined in the environment. The Wrapper now looks once and uses the same fully resolved path in both places. For clarity, both java command lines are now included in debug log output when the version is requested. (Bug #288) * Change the timing of the logging of the Java command line on UNIX so it is consistent with Windows. * Improve the error message text thrown when a native feature is not available from Java to be more clear about whether the problem is that the native library could not be loaded versus the wrong edition being used. * On Windows, detect when the Wrapper is running under Cygwin and set the default value for wrapper.console.flush to TRUE. On other platforms, the script will display a message and stop running. * (Professional) Add support for WRAPPER_EVENT_TIME_* and WRAPPER_EVENT_RAND_* variable references so event times can be used when events are fired. * Fix a buffer overflow problem on AIX which caused crashes or deadlocks on startup for some users. This had been an issue since 3.5.0 but only reported recently. * Remove output debug messages on UNIX when the wrapper.port.address property was set. * Clean up code when converting multibyte characters to wide characters. Some error checks were not implemented correctly. Found during a code review and is not known to have actually caused any problems. 3.5.24 * Fix a problem where the message source of remote syslog messages from the JVM were being logged as "jvm %d" rather than "jvm 1". * Add a new wrapper.syslog.split_messages property which controls whether or not multi-line messages will be logged as is or first split into individual lines. * Fix a problem on Windows Vista and above where the wrapper.single_invocation property was not correctly identifying Wrapper instances running in different sessions under some circumstances. 3.5.23 * Clean up the error messages logged when the Wrapper failed to elevate itself on Windows platforms. They are now more informative. * (Professional) Fix a handle leak on Windows in WrapperProcess.isAlive(). * (Professional) Modify the exception thrown when WrapperManager.exec is called while the Wrapper is shutdown so it now says that rather than saying that the native library is not loaded. * (Processional) The Wrapper is now more careful to make sure that the backend is never closed while a child process is being launched to ensure that the Wrapper knows about all child processes launched. * (Professional) Add a warning message in case the Wrapper is not notified of a launched child process due to the backend connection being closed. * (Professional) Fix a potential NPE that could be thrown while reading stdout or stderr output from a child process while the Wrapper was shutting down and after the child process exited. * (Professional) Fix a problem on UNIX platforms where we were getting stuck trying to cleanup after a process which was currently blocking on a read from stdout or stderr. * (Professional) Fix a problem on UNIX platforms where a timeout attempting to obtain an internal lock of the child process list was causing an internal counter to get out of sync, leading to a other terminated child processes being left as defunct zombies until the Java process terminated. * (Professional) Fix a problem on UNIX platforms where pipe file descriptions used to communicate with child processes were being incorrectly passed to all child processes. They were not growing over time. * (Professional) Fix a potential synchronization problem calling WrapperProcess.waitFor() or WrapperProcess.exitValue(). * Add additional debug log output showing the various timeout values to help with debugging user issues. * Fix a problem where the shell script was not correctly detecting the OS version with Mac OSX Maverick. * Add warnings about undefined environment variables in include file references in the configuration file. * Add support for environment variable expansion in files specified with the wrapper.java.additional_file and wrapper.app.parameter_file properties. * Correct the integer formatting in the WrapperUNIXGroup.toString() method so it is consistent with the rest of the Wrapper. * Fix a problem where the iconv library requirement couldn't be satisfied in FreeBSD 10. We now locate the library dynamically by looking for /usr/local/lib/libiconv.so, /usr/local/lib/libbiconv.so, or /lib/libkiconv.so.4 in that order. * Fix a the WrapperPrintStream.println method so strings containing linefeeds will correctly have each line prepended with the configured header. * (Standard, Professional) When an unknown license type is encountered, include the unknown type in the error message to help with debugging. * (Standard, Professional) Fix a problem on FreeBSD systems where the wrapper.lang.encoding was not resolving to UTF-8 correctly when the LANG environment variable was not set. * (Professional) Fix a memory corruption problem on z/OS when the language was set to a double byte locale like Japanese. * Go through and make the Wrapper much more durable when badly encoded double byte characters are encountered. 3.5.22 * (Standard, Professional) Fix a crash in native code behind WrapperResources instances which could happen if the system was very low on memory. Since version 3.5.7. * (Professional) Fix a couple slow memory leaks in the native code involved with launching and checking on the status of child processes. * (Professional) Fix a problem where an attempt to throw a WrapperJNIError within native code on Z/OS would result in a ClassNotFoundException being thrown. * Reviewed the native JNI code and fixed a few potential crashes and memory leaks which could occur under low memory conditions. * Modify the way the wrapper.console.direct property works so the Wrapper will now always downgrade itself to using piped console writing as soon as it has determined that a physical console does not exist. In 3.5.21 we tried to predict when the console would not exist and disabling it in advance. There were cases where this was not correct, resulting in error messages in the console output. * Fix a problem where operations like installing a service on Windows 7 and above which need to be elevated were resulting in an error that the Wrapper could not write to the console. The actual operation was working correctly but the console output was incorrect. Since 3.5.21. * Move the check that the jar and wrapper versions match earlier in the startup process so we guarantee that a warning will always be displayed. There were some errors which could abort the startup process before this warning was logged. * (Standard, Professional) Fix a problem where the value of wrapper.lang.folder was not being recognized if a wrapper.lang value was not set. * (Standard, Professional) Fix a small memory leak resolving the language to run the Wrapper with. * (Professional) Fix a potential buffer overflow reading data from a child process stderr or stdout if the amount of data available in the pipe is larger than the buffer length passed in to WrapperProcessInputStream. read(byte b[], int off, int len). * (Professional) Fix a problem where reads from a WrapperProcessInputStream were consuming too much CPU while blocking for data on Windows. Now correctly being done asynchronously. * (Professional) Fix a problem where JVM cleanup, including cleanup of child processes, was not always being done completely if the user requested an immediate shutdown by pressing CTRL-C twice. 3.5.21 * Add a new 'R' log format which will track the number of milliseconds since the previous JVM log output. Useful for simple performance checks. See the wrapper.console.format, wrapper.event.default.email.maillog.format, wrapper.logdialog.format, and wrapper.logfile.format properties. * When the ACCESS_VIOLATION testing command of the wrapper.commandfile was used to kill the Wrapper some log output was not making it into the wrapper.log file. Add a forced flush just before crashing the Wrapper to make sure everything makes it into the log file. * Add a new wrapper.javaio.buffer_size property which makes it possible to control the size of the internal buffer used to process console output from the JVM. Also increased the default from the system default to 65536 bytes. * Renamed the wrapper.use_javaio_thread property to wrapper.javaio.use_thread. The old property still exists as a deprecated alias. * Added a new wrapper.console.direct property on Windows which tells the Wrapper to use Windows APIs to render log output to the console rather than writing to stdout and stderr. This results in a major speed improvement. The drawback is that this removes the ability to pipe the output to another program on the command line. We chose to enable this by default so the majority of users can take advantage of the speed improvement. If your application takes advantage of piping on Windows, you will need to disable this property to regain the old behavior. * Add a new "wrapperm" logging source on Windows to help differentiate which log entries are coming from Wrapper invocations used to control the Wrapper as a service such as starting, stopping, installing, etc. Previously the log entries from the Wrapper service process and launching process both used a "wrapper" logging source, which could be confusing. * On UNIX, modify the way we keep track of whether the process is daemonized or not. This was done to clean up a bit, but should not effect how the Wrapper works. * On Windows, change the timing of when PID files are created when running as a service so any failures creating them will correctly be reported as a service error. If the Wrapper was unable to write to a PID file because it was read-only then the user was presented with a confusing message about the service timing out on startup. This was in addition to the correct error being logged. * Fix a potential problem where internally queued log entries could fail to be logged on shutdown. The log queue is now always processed as part of the shutdown process. * Modify UNIX shell script to remove all existing run level rc files for the application on both install and remove, rather than only the ones for the currently configured run level to avoid unexpected behavior due to old rc files being left around. This only affects platforms which make use of rc files. * Add a new RUN_LEVEL variable to the UNIX shell script to make it easy to configure the run levels when installing as a daemon on various platforms. * Add new wrapper.logfile.close.timeout and wrapper.logfile.flush.timeout properties, and deprecate the wrapper.logfile.inactivity.timeout property, to increase control over when and how the logfile is flushed and closed. * Add a new PIDFILE_CHECK_PID setting in the UNIX shell script which makes it possible to control whether or not the script double checks that the pid in an existing pidfile is actually the pid of the application's Wrapper. This property makes it possible to disable this check so multiple applications can be tied to the same pid file. * Go through and make sure that none of the Wrapper native JNI methods are called after the WrapperManager shutdown has completed. Doing so was causing a JVM crash on some Linux JVMs. This was happening when a WrapperResources instance was finalized by the garbage collector on shutdown. * (Professional) Fix a problem where processes created by calling the WrapperManager.exec functions could fail to be registered with the Wrapper for cleanup if the call was made as the JVM was shutting down. This was resolved by making sure that JNI calls can not be called after the WrapperManager shutdown has completed. * Modify the internal WrapperManager tick thread so it is allowed to complete once the WrapperManager has fully shutdown. This was the only remaining reference to the WrapperManager class. * Add a new wrapper.property_warning.loglevel property which controls the log level at which the Wrapper will log warnings about undefined but referenced environment variables, as well as invalid boolean or integer values. * Update the way environment variable references within property values are parsed to make it possible to report those which are not defined. Each pair of '%'s is now expected to be part of a variable reference. For example "%AAA%BBB%CCC%", previously if "AAA" was not defined, "BBB" would be located, but now only "AAA" and "CCC" will be recognized as variables. * Fix a problem on Windows where a non-existent wrapper.working.dir directory was causing multiple error messages in the log file. * Modify the way the wrapper.environment.dump property works so it will now log at the INFO level with the rest of Wrapper output when set to true. When false however, the output will be logged as DEBUG output if enabled. Previous versions always logged the output to the INFO log level in either case. * Fix a problem on Linux IA64 where the WrapperActionServer was throwing an IOException when the JVM was shutdown by calling System.exit. It did not cause any problems other than the message in the log. * (Professional) Added new "jvm_ping_timeout", "jvm_ping_slow", and "jvm_ping_response_slow" events to help respond to ping related issues. * Fix a problem where a value of 0 for wrapper.ping.alert.threshold was not correctly disabling ping threshold alerts. * (Professional) Fix a problem where the thread that handles events would permanently get stuck if the event queue filled up. This was very unlikely but not impossible if a large number of filter events were triggered in a very short time. Corrected the problem so it now recovers correctly, but also increased the queue size to make the overflow even more unlikely. * (Standard, Professional) Fix a problem where console output of a wrapperw.exe processes launched when the wrapper.ntservice.console property was TRUE was not being shown correctly. This issue was introduced in 3.5.19. 3.5.20 * Further improvements to the memory footprint of the Wrapper to minimize the memory required when logging JVM output consisting of very long lines. * Fix a minor potential buffer overflow, which could occur if the path of the first classpath element is larger than 1024 characters. This overflow was detected during a code review and we have no reports that it actually ever caused any problems. * Improve the error message displayed when the Wrapper's configuration file could not be loaded so that it now includes the name of the file. * Work around a libc system library bug on some HPUX platforms in which calls to vswprintf can cause a crash if the expanded string does not fit into the buffer. Worked around the problem with the help of HP support by making sure the buffer length followed a rule so that its length was 1+N where N is a multiple of 8. * Fix a problem on HPUX platforms where the JVM would sometimes get stuck on shutdown, when the shutdown was initiated within the JVM, leading to the Wrapper having to forcibly kill it. This was caused by the Wrapper attempting to close the backend socket when another read was blocking attempting to read from the same socket. This was introduced in version 3.5.8. * Fix a potential log corruption when queued log messages were larger than the internal buffer size. Found during a code review and is not known to have actually caused any problems. * Fix a typo in the shell script which was breaking the 'install' command on Solaris platforms. * Fix a potential crash on HPUX platforms if the value of the wrapper.port.address property had an encoding problem. 3.5.19 * Fix a problem in the batch file, where a space in the path to the Wrapper.exe file would cause the script to locate the Wrapper.exe file. Introduced in 3.5.18. * When running as Windows service with hiding the console of the Wrapper will cause the Wrapper to disable unnecessary logging to the console in order to enhance performance. 3.5.18 * Fix a problem, where an unclosed percentage character '%' was opening the chance of a dangling pointer in the additional java parameters. The '%' character is a special character, specifying an environment variable. * Added variable _WRAPPER_DIR the batch files to make it possible to specify any other directory where the Wrapper binary file is located. Until now the batch file and exe file had to be in the same location. Thanks and credits go to Geoff. * Added property wrapper.port.address, which makes it possible to specify a different address to bind the socket to when using the socket backend connection between the Wrapper and the JVM. Until now, the socket was always bound to the localhost loopback interface. * The script will from now on also use the update-rc.d tool for installing an application as daemon on Debian. Thanks and credits go to Haifeng. * Whenever the Wrapper is causing the JVM to be forcibly terminated, the Wrapper will make sure the JVM has actually been terminated. If it wasn't after wrapper.jvm_terminate.timeout seconds, a pending restart will be canceled and the Wrapper exit. * Reworked the way the Wrapper is processing output from the JVM, in order to increase performance on huge output on a single line and also reduce memory usage. 3.5.17 * Add a new wrapper.java.additional.default.stripquotes property to make it possible to specify the default value of wrapper.java.additional..stripquotes * Fix a bug where the timer failed to calculate the fire time when that time was more than one week in the future. This was possible for weekly timers which spanned a daylight savings time change which rolled the time back by an hour in the fall. * Fix problem in the shell script, where it might fail to remove an installed daemon after the location of the script has been changed. * Add additional advice messages when a Windows service fails to be started due to file access problems involving the Wrapper binary, configuration, or log files. * Fix a problem where the dynamic library on MacOSX was not able to load it's functions. * Added wrapper.app.parameter_file property, which works similar to the wrapper.java.additional_file property * Reduce CPU-consumption of WrapperProcess.waitFor() function 3.5.16 * (Standard, Professional) Retry failed share mappings if the target host or network is unreachable as that may be a temporary problem. * (Professional) There was a problem where the IO-redirection of a child process which got created with the WrapperManager.exec API and used the feature to run the child process in the logged on users desktop was only allowing to create a process once per second. * Include information about the base configuration file in the debug output when debugging of cascading configuration files has been enabled. * Add a check in the UNIX script to output a more descriptive error message, when the user specified in the RUN_AS_USER variable doesn't exist. * (Standard, Professional) Fix a problem where console log output was not being displayed correctly when running with the WrapperW.exe binary with the wrapper.ntservice.console property was set to true. * (Standard, Professional) Implement the wrapper.ntservice.generate_console property when using the WrapperW.exe binary so it is now possible to disable the creation of the hidden console. * Modify the way the the wrapper.ntservice.generate_console property works so it is now easier to disable the generation of the console using just this property. * Improve the message logged when the the Wrapper attempts to perform a thread dump without a valid console being available. * Add new wrapper.ping.alert.threshold and wrapper.ping.alert.loglevel properties which make it much easier to debug ping timeout issues by asking the Wrapper to log messages about ping responses which were shorter than the registered wrapper.ping.timeout, but longer than the threshold. * Add a new WrapperManager.appearSlow method which makes it easier to test how the Wrapper behaves when the JVM is being slow to respond to commands. * Add a new wrapper.disable_tests property which can be used to disable all of the testing methods of the WrapperManager class. It has always been possible to control their access with a SecurityManager, but this is simpler for most applications. * Update the default wrapper configuration file template so a restart due to a matched OutOfMemoryError filter will no longer be triggered by default if the user enables -verbose:class output. * Fix a problem on UNIX platforms where the Wrapper would fail to start if it was located on the system PATH. This had been a problem since version 3.3.0 but had gone unnoticed as the Wrapper is not usually referenced in this way. * Rework the internal flags governing the generation and hiding of the backend console on Windows so we are able to almost always obtain the console's window handle. * Cleanup some startup code to reduce duplication and make sure that more debug and warning messages are logged after the "Wrapper Started" message. * Add new wrapper.java.additional_file and wrapper.java.additional_file.stripquotes properties to make it possible to specify JVM parameters in a file. * Add support for Linux on ARM systems. * Re-Enabled the forced reloading of the SYSTEM (and if set to a specific account, the user) registry before launching the Wrapper as a service on Windows XP and 2003. This has been originally disabled for Windows XP and 2003 since version 3.5.5. * (Standard, Professional) Fix a problem where the instance class names logged when a deadlock involving ReentrantLock instances were corrupted. The actual deadlock detection was working correctly, but this could have lead to other problems caused by the corruption. A workaround was to set the wrapper.check.deadlock.output property to SIMPLE. * (Standard, Professional) Make it possible to completely disable the details of a deadlock by setting the wrapper.check.deadlock.output property to NONE. * (Standard, Professional) Object Ids in thread dump reports were not correctly being logged as 64-bit ids on 64-bit JVMs in some cases. * Fix a problem where the source code values returned by the WrapperServiceActionEvent.getSourceCode() method were incorrect. The constant values were incorrect and have been corrected from this release. * Add new WrapperServiceActionEvent.getSourceCodeName() and WrapperServiceActionEvent.getSourceCodeName(int actionSourceCode) methods which returns a localized name of the source where the event originated. * Fix a minor problem where a couple uncommon backend packet codes were not being correctly identified by name in the debug log output. Functionally they were all working correctly. * Added property wrapper.ping.timeout.action, which will let you specify an action in case the timeout triggers. So far the only action was to restart the JVM. * Fix a problem where a JVM process was not stopped completely on a UNIX platform and stayed defunct after a forced kill until the Wrapper process itself stopped. This was especially noticeable if the JVM is frozen and the JVM is being killed forcibly. * Add additional debug log output showing the various timeout values to help with debugging user issues. 3.5.15 * Add a new _WRAPPER_CONF_OVERRIDE setting to the Wrapper dedicated command batch files on Windows so it is now possible to control whether or not the first parameter is the configuration file name. The ability to specify an alternate configuration file is now disabled by default as it was confusing for users who tried to pass other parameters to the JVM. * Correct a couple log messages in the WrapperManager class which were missing the correct prefix identifying where they originated. * Remove some old reflection code needed for Java 1.2.x support as we have required Java 1.4 since version 3.4.0. * Remove some code to try to reconnect the backend socket from Java. It has never been possible to do so without restarting the JVM, and the related messages were confusing. * Add a new wrapper.disable_forced_shutdown property to make it possible to disable the feature to forcibly kill the JVM on shutdown if CTRL-C was pressed twice. * Reduce the number of times thread priorities are changed within the WrapperManager class to simplify the startup and shutdown process. * Fixed a dangling pointer problem, which could cause undefined behaviour whenever a property contained an unset environment variable. * Fix a race condition in the timer thread, which could cause a sigkill being propagated through the whole process group rather than the timer thread. This can only happen during the shutdown of the Wrapper. * When a child process, which got launched by WrapperManager.exec() failed to start due to a runtime-error (such as missing privileges), the forked heap persisted and the child process never finished until shutdown/restart of the JVM. The error only appears on Unix platforms when using the FORK_EXEC start-type. * Change log level and message if a certificate check returned a problem, which is not directly caused by the signature of the Wrapper, but the signature chain. * Fix a problem when the silent query command wasn't returning the correct exit code on windows Vista (and later) when the command was run from an unelevated console. Thanks to Darren for pointing this out. * The java system property wrapper.backend.so_timeout was ignored if it was set to 0, making it not possible to explicitly set the timeout to be indefinitely. * Added the properties wrapper.jvm.additional.auto_bits. to individually turn on/off the feature for the supported platforms. * Fix a problem where the script was trying to use the 64-bit binaries on Mac OSX even if the CPU was only a 32-bit architecture. This only affected versions of Mac OSX greater 10.5.0, the vast majority of those machines are already 64-bit CPU's. * The Wrapper when reloading the configuration file, was trying to access data from the call stack of a function which was actually outside of the memory range of the stack. This access violation might yield a segmentation fault. This issue was introduced in 3.5.5. Thanks to Lincoln for helping finding this problem. 3.5.14 * Fix a problem in the AppCommand.bat.in file where a parenthesis in the file name of the Wrapper binary would have caused a "PATH was unexpected at this time" error. * (Standard, Professional) Fix a problem when using a localized version of the Wrapper on Windows 64-bit platforms where the Wrapper would continue to use the default system language even wrapper.lang was used to specify a different language. Introduced in 3.5.12. * Fix a problem in the Windows AppCommand.bat.in command based batch file where the 'status' command was incorrectly being reported as 'query' in the usage output. The 'status' command had always worked correctly if used. * Fix a problem on UNIX platforms where some asynchronous messages were causing a warning message "Coding Error..." to be logged in place of the intended message. This could be seen if the configured log file did not have write permissions. Other than the incorrect log message, the Wrapper worked correctly. Introduced in 3.5.2. * Fix a problem in the UNIX script where running with Upstart wasn't working correctly when RUN_AS_USER was set. * Relax security checks when running the 'status' command against the UNIX shell script so it now allows any user running the script to perform the read-only check of the pid file. * Fix a problem with the UNIX script where the 'remove' command was trying to stop a running application even when the application had not been installed. * Fix a buffer overflow which could potentially cause a crash during the installation of a Windows Service when wrapper.ntservice.account was specified. This was introduced in 3.5.12. * Fix a heap corruption which could occur on startup and potentially cause a crash. Only Windows systems, which use the System Event logs, were affected. Discovered from a code review, there had never been any reports of this causing problems for users. This could happen if the configured wrapper.log could not be written to as the Wrapper always tries to write to the Event Log in such cases. Introduced in 3.5.12. * Add a new version comparison between the UNIX shell script and Wrapper to start showing a warning in case of a version mismatch. The check will only work if the shell script and Wrapper are each of at least version 3.5.14. * Added a new wrapper.pidfile.strict property which will tell the Wrapper not to start if the pid file already existed. Defaults to false for backwards compatibility. * Make the Java side of the backend socket more resilient in case of a read or write timeout. The backend socket does not have a timeout set by default so this should not have been an issue. A couple users reported problems on specific systems however which led to this fix. * To aid in the testing of the backend socket timeout, a new wrapper.backend.so_timeout system property was added to make it possible to configure the backend socket to use a timeout. See the Javadocs of the WrapperManager class for details. 3.5.13 * Fix a typo in the script where the environment variable 'TR_BIN' should actually be 'TREXE'. This was causing the "install" command on UNIX platforms to fail. Introduced in 3.5.12. * Fix a heap corruption which could lead to a crash that would occur the second time an internal buffer used for logging was expanded. The buffer would be expanded the first time a log line over 2048 characters in length was encountered. Then the second expansion would happen when a line at least 1024 characters longer was encountered. Introduced in 3.5.11. Bug ID #3423108 3.5.12 * Put more descriptive Text in case the Wrapper is using integration method 4, but the jar file deos not specify the Main-Class correctly in its meta information. * Fix a bug when failing to grant the LogOnAsService permission to a domain user. * Fix a bug where the ident for the syslog on Unix platforms was broken since 3.5.0. This was because when opening the syslog, the Wrapper was freeing the memory for pointing to ident. However the string pointer ident will be retained internally by the Syslog routines. And must not free the memory that ident points to. Bug #3404978. * Add a check on the script to make sure the 'tr' command exists on Unix platforms. * Improve the parsing of log formats so that format tokens are recocognized even if they are lower case. This affects the wrapper.console.format, wrapper.event.default.email.maillog.format, wrapper.logdialog.format, and wrapper.logfile.format properties. * The Wrapper parses log formats by looking for known tokens, any invalid tokens are simply ignored. If the entire format is made up of invalid tokens then this resulted in the Wrapper logging an empty line, which was not very useful and caused confusion when encountered. The Wrapper now reverts to the default log format in such cases. This affects the wrapper.console.format, wrapper.event.default.email.maillog.format, wrapper.logdialog.format, and wrapper.logfile.format properties. * Improve the debug output while loading native libraries to avoid confusion about the meaning of the warning logged about attempts to load alternately named native library files. * Fix a problem on Unix platforms where the default umask was being set to 0000 rather than inheriting it from the parent process when running as a daemon process. This can be a security problem as log and other files have global read/write access. Introduced in 3.5.8. Can be worked around by setting the wrapper.umask property to a safe value. 3.5.11 * Fix a potential crash on Windows caused by a buffer overflow. This has been a problem since version 3.5.0 and affects configurations which define more than one wrapper.ntservice.dependency.. Depending on what was in memory, this did not always result in a crash. It has very reproducible behavior for a given configuration file. * Fix a problem on Windows where the Wrapper was taking 15 seconds or longer to startup on some systems because the WinVerifyTrust system call was having problems updating the CRL. This had been a problem since the Wrapper binaries started being signed in version 3.5.7. If the WinVerifyTrust call takes longer than the configured wrapper.startup_thread.timeout then the Wrapper will continue to startup without further delay. * (Standard, Professional) Explicitly remove the certificate of the customized binary during customization. There were problems resigning the binary with another certificate otherwise. * If the Wrapper is unable to write to the configured wrapper.logfile for any reason then we always fall back to a default log file and then log a message about the failure. If the default also fails then that is also logged but the messages would only be logged to the console in most cases. Modify the Wrapper so we now always send both messages to the syslog or EventLog regardless of what the wrapper.syslog.loglevel is set to. This is important to help track down the cause of logfile access problems. * Starting with version 3.5.0, it was internally possible to print out multi-line log messages so that all of the lines would always be grouped together in the log file. This version modifies the logging code slightly so that such multi-line log output is now logged as a single message in the UNIX sylog or Windows EventLog. * Fix a problem where very long lines of output from the JVM would cause the Wrapper to appear to hang for a while. The first time a single line of output containing several hundred thousand characters was logged, an internal buffer was being incrementally increased by 100 characters per cycle. The Wrapper now increases the size based on last known size to greatly reduce the number of cycles needed to choose a new buffer size. * Modify the PAUSE_THREAD command so it is now possible to wait indefinitely. Only useful for testing the Wrapper. * Add a new PAUSE_LOGGER command to make it possible to pause the next log entry. Only useful for testing the Wrapper. * On UNIX, the stdout/stderr pipe between the JVM and Wrapper was not being cleaned up correctly. This resulted in a small leak but was otherwise harmless. The pipes are now cleaned up and initialized for each JVM instance. * Fix a problem where the Wrapper could fail to restart the JVM when the restart request originated in the JVM if the system was experiencing very heavy IO resulting in long disk IO queues. This was causing the Wrapper's main loop to block on the write and miss the restart request, causing the Wrapper to shutdown rather than restart. This could affect all platforms. On Windows, it could also be reproduced by making a selection in the console to freeze output and then making a request from within the JVM to restart. * Add a new WrapperPropertyUtil helper class to make it easer to access Wrapper property values from within the JVM. * Fix a bug on some platforms where java log output could get corrupted due to misuse of a strncpy system function. This function warns that some implementations do not support overlapping memory copies. The problem could only be reproduced on a single Linux test machine in lines following an empty line of output. This problem has existed since 3.4.0. 3.5.10 * Setting wrapper.jvm.port to '0' (zero) will make the JVM to assign an available port for the backend socket by itself. * Add warnings in the log file if an integer configuration property value contains a non-numerical value. Previously, the Wrapper would silently ignore the problem and use the value of 0 if the number started with an invalid character, it will now return the default value. If the property value started with valid numerical characters then those were, and still will be, used to generate a value, but the invalid characters will be trimmed. The later is being kept this way to avoid breaking old configurations. * Add warnings in the log file if a boolean configuration property has any value other than TRUE or FALSE. It will still return a value of FALSE for other values to avoid breaking old configurations. * Add a warning if an invalid value is specified for the wrapper.on_exit. property. * Add a new wrapper.log.lf_delay.threshold property which makes it possible to control how long a partial line of Java log output will be allowed to be buffered until it is completed with a line feed. If the threshold is exceeded then the partial line will be logged as a full line resulting in an extra line feed in the log output. All previous versions would do this within 1-2 ms. The default is now 500ms. * (Standard, Professional) Make it possible to customize the manufacturer through the customize options. * (Professional) Fix a problem where the Wrapper was sending a CTRL-BREAK rather than a CTRL-C signal to child processes launched with WrapperManager.exec when destroying them on Windows. For most child processes this was not a problem, but if the direct child process was a JVM then the CTRL-BREAK was triggering a thread dump rather than asking the JVM to exit. The Wrapper was then timing out and forcibly killing the JVM child process. * (Standard, Professional) Fixed a bug, where the timezone ICT when set by the wrapper.timezone property got misinterpreted as IST. * (Standard, Professional) Fixed a problem where the UTC offset value in the wrapper.timezone property was not being parsed correctly on UNIX platforms. This led to the Wrapper to using an offset UTC0000. * Take out the warning about unset LANG environment variable on Linux and AIX systems. On system startup, some systems fail to set the LANG environment variable. This is not really a problem for the Wrapper and the warning was causing confusion for users so we decided to remove it. 3.5.9 * (Standard, Professional) Fix a problem on Windows where network adapters whose names contained "PRO/1000" were being removed from the list of hostids displayed when "wrapper.exe -h" was run. This did not affect existing server license key files generated for hostIds reported by 3.5.7 or earlier, or development license keys. But it did cause the Wrapper to report that no valid hostIds could be found when the Wrapper was started without a license file. This was caused by some test code added in 3.5.8 that we failed to remove. * Fix a problem where the Wrapper was not correctly yielding control back to its main loop when very large amounts of continuous output was being logged from the JVM. Introduced in version 3.4.0. In versions prior to 3.5.8, this could have caused the JVM to timeout and restart itself. That particular issue was resolved but the Wrapper process in 3.5.8 would still have been unresponsive when this was happening. The Wrapper will now always yeild back to its main loop after 250 milliseconds of continuous logging. * Fix a problem where the WrapperManager could block trying write debug output if the current user application was writing very large amounts of output to the console as well. In extreme circumstances this led to the Wrapper thinking that the JVM was frozen. This was only an issue if debug output was enabled. * Restructured the shell script so all editions now use the same script again. 3.5.8 * (Standard, Professional) Starting with version 3.5.5, we invalidated the use of all 00ff* hostids on Windows to avoid problems with changing hostids when users have a Juniper Network Connect network adapter on their system. This turned out to be too restrictive as Guest OSs running under Parallels also make use of this hostid range. The Wrapper is now more careful to only invalidate actual Juniper Network Connect hostids. * (Standard, Professional) Improve the message shown to the user when the Wrapper is unable to locate any hostids for a system. * Fixed a problem with the wrapper script on Solaris, where the option -F was not available for grep. * Added Windows version information on the wrapper debug output. * Added a wrapper.log.warning.threshold property which makes the Wrapper show a warning whenever it detects that the Wrapper took a long time to record a log message. This was added to test a reported issue caused by slow IO on very heavily loaded systems. * Added a new 'G' log format to log the time in milliseconds of the previous log message. See documentation with the wrapper.log.warning.threshold property. Added to the wrapper.console.format, wrapper.logfile.format, and wrapper.logdialog.format properties. * Fix a problem where a filter that requested the JVM to restart would be ignored if the JVM exited on its own immediately. The Wrapper is now more consistent so that restart requests from within the JVM or filters will always take priority over such exit requests. External shutdown requests, or those from other actions will still behave as they did in the past and continue to shutdown the Wrapper. The Wrapper also logs messages in debug output if an outstanding restart request is being preserved or ignored. * Fixed a problem in the AppCommand.bat batch file which could occur on some Windows platforms with certain multi-byte system encodings. The script has been rewritten and questionable parts have been simplified. The functionality of the script has been preserved. * Added the environment variable WRAPPER_CONF_DIR, which can be used for the configuration properties. Feature Request #3160644. * Made the script exit with the right exit code received when running the script as different user, specified in RUN_AS_USER. Bug #3185281. * Fix an access violation which could happen when reporting that the code signing certificate has failed to been verified. * Log an error if the backend socket is forcibly closed externally. It had been getting logged at a debug log level. The message is "An existing connection was forcibly closed by the remote host. (0x2746)". Because the message was only logged if debug output was enabled, the JVM would be restarted with no clear explanation as to what happened. The source of the socket closure is under investigation. * (Professional) Added the Java call fireUserEvent to the WrapperManager API. This enables to fire user event mails, actions without the filter trigger. * Fix a warning on Mac versions if the configured java command was not a universal binary. A check was added in 3.4.0 to make sure that the wrapper.java.command pointed directly to an executable to avoid unexpected behavior when running a script. The message is only a warning and the Wrapper continues regardless. Standard ppc, ppc_64, x86_64, i386, as well as the universal binaries will now all work correctly without a warning. * The default value of the wrapper.*.umask properties is using the current umask the process has. Before the default value was always 0022. * Add a new wrapper.backend.type property that is used to control whether the Wrapper communicates with the JVM using the traditional "SOCKET" or new experimental "PIPE". This was added as a workaround to a rare problem where some Windows machines are closing the socket at an OS level. This was only ever seen on Windows 2003, but could exist on other Windows versions as well. * Add a new experimental wrapper.use_javaio_thread property which causes the Wrapper to handle all java console output in a dedicated thread. * Add a new WrapperManager.isNativeLibraryOk() method which lets user code easily test whether or not the native library was loaded and initialized on startup. * Add a new PAUSE_THREAD command to the wrapper.commandfile property which makes it possible to test how the Wrapper behaves when various threads block or freeze. This was used to simulate and reproduce issues on heavily IO bound servers. * Improve the way the Java side of the Wrapper behaves when the Wrapper fails to ping the JVM for an extended period of time. The JVM used to exit to let itself resync itself with the JVM. This was causing problems on systems which were heavily IO bound because the Wrapper could block for a while while trying to write to the log file and the JVM was exiting. The JVM will now never exit under such circumstances. The JVM will never become orphaned because it will still exit almost immediately if the backend socket or pipe with the Wrapper is ever closed. * Deprecate the WrapperManager.appearOrphan() method as it is used to simulate a failure mode which is no longer possible with the Wrapper. * Changed the way the Wrapper is handling certificate errors regarding the code signing/timestamping certificate. The Wrapper will now only shutdown itself if the signature of the binary was not successfully verified because the binary or signature has been malformed but not if any problem with the counter-signer has been found. Starting with 3.5.7, the Windows Wrapper binaries are signed. Some users with locked down Windows 2008 systems had problems with the Wrapper refusing to start because the Comodo certificate had been disabled on their system. * Add a new wrapper.java.detach_started property which makes it possible to use the Wrapper as a simple tool to launch Java applications. When enabled, the Wrapper terminates immediately and the JVM is left to run on its own. Also add new wrapper.java.outfile and wrapper.java.errfile properties which make it possible to redirect the stdout and stderr of the JVM to files when detached. * When running the Wrapper as a specified User Account, through the wrapper.ntservice.account property, the Wrapper will add permission for the account to log on as service automatically upon install. Feature Request #3286491. * Fixed a problem binding the backend socket on Windows. If another process bound a port inside the wrapper.port.min and wrapper.port.max range using the SO_EXCLUSIVEADDRUSE option, the Wrapper would stop at this port report an Access Permission problem and omits binding any further port in the range. This problem existed ever since the Wrapper was released. 3.5.7 * Changed the way the script is installing the daemon gets installed on an AIX system. The script now uses inittab & SRC. * Fix a problem in the shell script that was preventing the script from starting the Wrapper correctly if a file or directory existed in the current working directory which was one character in length. This was only a problem when the delta-pack naming of the Wrapper was used. This was easy to reproduce on AIX systems on system restart because a "u" directory exists in the root directory by default. This had been a problem since 3.4.0 when it was introduced as a fix to a Solaris problem. The root cause was a missing set of quotes in the tr command. * Fix a problem in the shell script that was preventing the script from finding the running wrapper process when it was started when the working directory was in the same directory as the wrapper binary, but queried later from another location. It would also fail if it was started from another location, but then queried from the location of the Wrapper. This was introduced in version 3.5.6 when the script stopped changing the working directory in the script. * Add a new GC action that will cause the JVM to immediately perform a full garbage collection sweep. See the wrapper.commandfile, wrapper.filter.action., wrapper.check.deadlock.action, and wrapper.timer..action properties for details. * (Professional) Modify the wrapper.event..command.block.action property slightly so it will now correctly warn if an unknown action is encountered. It had been defaulting to CONTINUE silently. * Modify the timing of the message shown when an #encoding directive is missing from the top of a configuration file. It was only being logged if debug output was enabled. It will now also be logged if the #include.debug directive is specified. * Fix the indentation of warning messages about encoding or include problems in configuration files. * (Standard, Professional) Fix a problem where include file problems could cause the shell script to have errors due to invalid translated output from the Wrapper. * Add a warning when the maximum include depth is reached and include debugging is enabled. The Wrapper had always just silently skipped the include. * Fix a problem where #include.required directive was not correctly preventing startup if the include file was missing but the required include was in a nested include. * Fix a problem where the cause of some fatal include problems were not being logged correctly, resulting in a simple, non-informative message only that the configuration file failed to be loaded. This was a problem since 3.5.5. * Fix a Windows problem where the Wrapper could fail to start as a service if a defined environment variable would expand to a length larger than the 32k limit specified in the ExpandEnvironmentStrings system function. This was a problem on all Windows platforms prior to version 3.5.5, but only on Windows 2000 since then, when the code used to reload the environment from the registry was disabled for newer versions of Windows. We now simply skip the expansion of the problem variable and continue with a warning. Bug #3103776. * Add a set of optional system properties that the WrapperSimpleApp, WrapperStartStopApp, and WrapperJarApp helper classes are aware of to tell them to ignore uncaught exceptions thrown within the main methods of the user application. The exceptions will still be logged, but they can now be configured so that the main method is just allowed to end without causing the Wrapper to shutdown in an error state. Java on its own will stay running in such a case as long as it has launched at least one non-daemon thread prior to the uncaught exception being thrown. This does not affect most users, but an application was found that was having problems because of this difference in behavior. See the javadocs of the helper classes for details. * (Professional) Fix a problem when looking for the correct exit code to use for the wrapper.event..command.on_exit. property. The Wrapper now searches for a value as follows: wrapper.event..command.on_exit., wrapper.event..command.on_exit.default, wrapper.event.default.command.on_exit., then wrapper.event.default.command.on_exit.default. The third pattern had been getting skipped in previous versions since it was added in version 3.3.0. * (Professional) Add logic to report a warning if an unexpected value is specified for the wrapper.event..command.on_exit. or wrapper.event..command.block.action properties. * (Professional) Clean up the message log levels so the output is as expected when using the wrapper.event..command.loglevel property. * (Professional) Improve the wrapper.event..command.on_exit. property so the configured action will now work even if the command exits after the block time out has expired. In previous versions, there was no way to make the Wrapper do anything other than continue. * (Professional) Fix a problem where the Wrapper was failing to detect a JVM exit correctly if an event command had been fired first. The only problem was that the Wrapper was always reporting a JVM exit code of 0 rather than the actual exit code. * Fix a buffer overflow on Windows when either installing as a service, or updating an existing service. The problem only occurred when properties containing spaces, or Java passthrough arguments containing spaces were specified on the command line. The running service did not have any problems. This was introduced in 3.5.0. * (Standard, Professional) Improve the error message logged when an unlicensed version of the Wrapper's native library is used. * (Standard, Professional) Fix a buffer overflow problem on Windows when creating a customized Wrapper binary if the target binary name did not include the ".exe" extension. This problem existed since its intruduction in version 3.3.7. * The wrapper.exe, wrapperw.exe and wrapper.dll binaries are now being signed on Windows making it possible to verify that valid Tanuki Software binaries are being used. * Implemented a way to install, remove, start, stop, etc., the Wrapper as a Windows service from a non-elevated (UAC) console. The Wrapper is elevated transparently using a child process. This is needed starting with Windows Vista and 2008 for smooth interaction with the Windows Service Manager. * (Standard, Professional) Fix a problem where the wrapperjni_*.mo localized files were not being loaded correctly. These messages are only shown when debug output is enabled. Application and Wrapper localization was working fine. Introduced in 3.5.5. * (Standard, Professional) Enhanced the ability to run with localizations other than the system language on Windows. The Wrapper process locale was not being set correctly. So Japanese text was not always showing correctly if the wrapper.lang property was set when the OS was English or German. The Java process still has an issue where it will always start with the system default value for the file.encoding system property. This can still cause problems writing Japanese text when the file.encoding is German for example. * Added support in the shell script for starting/installing the wrapper on system boot with Upstart. * Fix a problem in the shell script where it would fail to recognize a running Wrapper if the Wrapper command line or path contained a square bracket. * Modify the way we test for the existance of the temp directory so we now generate our own file name rather than using File.createTempFile. On some systems createTempFile was taking a long time because it requires that Java initialize its internal entropy. We discovered that large numbers of files in the java.tmpdir directory makes Java's entropy initialization code very slow. This has been a potential issue since 3.5.0. * Fixed a problem on Windows where passthrough arguments after a "--" which contained spaces were not being passed through to the JVM intact, they were being split at the spaces into multiple arguments. * Fix a problem on Windows where the Wrapper could sometimes crash on shutdown if more than one thread got into the cleanup code at the same time. This did not affect running applications and was only an issue on shutdown. It was more likely if a language pack was loaded. Introduced in 3.5.3. 3.5.6 * Fix a problem on UNIX platforms where the log file path was being calculated incorrectly if an absolute path was specified for wrapper.logfile, and the file did not already exist. A warning message was being displayed but the Wrapper would continue using the default log file. There was a problem in the message displayed which caused a crash on some platforms include Mac OSX. Introduced in version 3.5.5. * Fix a problem on Windows platforms where the Wrapper would crash if it could not access the directory of the configured wrapper.logfile. Introduced in version 3.5.5. Bug #3087424. * Improve the way warnings are logged when there are problems writing to the configured wrapper.logfile so that the message will now be logged into the log file that the Wrapper ends up using in case it is successful in falling back to a default log file. * Fix a problem on Windows platforms where wrapper.java.additional. properties that were specified on the command line, and contained spaces, were not being requoted correctly when building up the Java command line. Introduced in version 3.3.6. * Fix a problem where the warning message logged for invalid values of the wrapper.java.additional. property, contained corrupted text. Introduced in version 3.3.6. * Fix a problem on UNIX platforms where an invalid value for the wrapper.java.additional. property was correctly being reported and then skipped, but the resulting command line to launch the JVM had a blank value that was causing the JVM to fail to launch. An invalid value is any value that does not begin with a "-" character. * Add a new WRAPPER_INIT_DIR environment variable which can be used to reference the working directory from which the Wrapper was launched. This is needed for certain applications because the Wrapper always changes its working directory to the location of the Wrapper binary. * Modify the UNIX shell script so it no longer changes the current working dir to the location of the script. This is no longer needed because the Wrapper has been changing the working directory to its own location since version 3.2.0. * Add a new wrapper.request_thread_dump_on_failed_jvm_exit.delay property to control how long the Wrapper will wait after doing a thread dump before killing the Java process. This delay has always been hardcoded to 5 seconds. * Clean up the text of several warning messages about invalid configuration values to make them more consistent. * (Professional) Add a new wrapper.jvm_kill.delay property which makes it possible to control the amount of time to allow between the jvm_kill event being fired and the JVM actually being killed. Useful if an external event command is fired that needs to do something with the JVM process first. * (Professional) Fix a problem where the output of the wrapper.event..message and wrapper.event..loglevel properties were not displaying correctly on UNIX platforms. * (Professional) Fix a problem on UNIX platforms where the Java side of the Wrapper was not being correctly notified if a large number of child processes that had been launched with WrapperManager.exec, exited at the same instant. Some of them were going into a defunct state until the next child exited, at which point they would be cleaned up. This was mainly an issue on JVM shutdown if the user code was calling WrapperProcess.waitFor() as part of its shutdown process. WaitFor calls at any point were getting stuck and would remain so until another child exited. As part of this fix, there were also several changes to the Windows implementation to bring the two code bases into sync. * Fix a problem on Windows when multiple threads were creating Childobjects, Handles could have been unintendedly get inherited by another Child Process, causing problems on reading/writing to the Input/Output/Errorstream. * Fix a problem on solaris and AIX when errno calls were not thread safe due to a compiler switch. * Fix a problem where debug level warning output while loading the Wrapper configuration was being displayed on startup. This could be fixed because the Wrapper actually loads the configuration twice, and such output is now only logged on the second call. * (Standard, Professional) Remove the undocumented ability to define a single file share mapping without the index. This would cause confusion if used, and complicated the code. * (Standard, Professional) Fix a byte alignment problem caused by a bad compiler directive on Windows platforms. It was known to cause a crash when defining mapped drives on 64-bit Windows versions. The problem was in the source since version 3.3.7, but is not known to cause any other issues. * (Standard, Professional) Modify the messages displayed when network shares are mapped or fail for some reason. Also add messages about them being unmapped on shutdown. * On some Windows platforms, a failure to delete a rolled log file was not being reported correctly. The system function to delete a file was returning success even if it had failed. We now double check. * Fix a deadlock in the code that is used to send data to the Java process. It was only possible if debug level output was enabled and log file rolling was enabled. Introduced in 3.3.7. * Fix a problem where the Wrapper was not notifying the JVM whenever the log file was rolled and the new name was the same as the previous one, as it is when wrapper.logfile.rollmode is anything other than NONE or DATE. * Fix a problem where the WrapperManager.getWrapperLogFile() was not returning the accurate log file name until the first time the log file was rolled after each JVM invocation. This was only noticeable if the wrapper.logfile contained either the "ROLLNUM" or "YYYYMMDD" tokens. * Correct an error message that was displayed on UNIX platforms when the configured java binary could not be accessed. The message referenced a buffer whose contents were undefined on some platforms. * Fix a problem on z/OS where due a difference in the API used to lock a mutex compared to all other UNIX platforms, the mutex's locking and unlocking code were effectively being ignored. This means that multiple threads were able to access code which was not thread safe and could lead to a crash of the Wrapper. This is a problem that has been in the code since the first z/OS release and is not known to have actually caused any problems. Starting with 3.5.1, this was only an issue if debug output was enabled. Versions 3.3.9 through 3.5.0 could have also had problems whenever the Wrapper received a system signal. 3.5.5 * Add new wrapper.filter.trigger. action, "SUCCESS". If this gets triggered then the Wrapper will treat the current JVM invocation as a success, and reset its internal failed invocation counter. This is useful for applications that need to be restarted frequently. * (Standard, Professional) Ignore Juniper Network Connect hostIds as they change on each reboot and are thus unreliable as hostIds. * Added a PASS_THROUGH setting to the UNIX shell script and Windows AppCommand.bat.in files which tells them to pass any extra arguments directly on to the JVM when it is launched. * Added a FIXED_COMMAND setting to the UNIX shell script and Windows AppCommand.bat.in files to make it possible to run either without specifying a command. Mainly useful in conjunction with PASS_THROUGH. * (Standard, Professional) Added a --passthrough option to the exe customization, in order to tell the wrapper to precede the whole command line through to the application in the JVM. * (Standard, Professional) Added a --conf option to change the default conf file, the wrapper tries opening when no conf file was explicitly specified. * Added wrapper.ntservice.account.prompt. If set to TRUE the wrapper will prompt for all account details (domain, account name, password). * Fix a minor issue in #include file declarations where a leading space was not required. * Add a new #include.required directive which works the same as the #include directive except that it will output an error and prevent the loading of the configuration if the included file does not exist. Normally include files are optional by design. * Modify the error messages displayed when configuration files fail to load so they now provide more information about where specifically the problem was. * Disabled the forced reloading of the SYSTEM (and if set to a specific account, the user) registry before launching the Wrapper as a service on Windows. This was done originally in Windows NT because changes to the configured environment were not being reflected when running a service unless the system was first rebooted. Microsoft appears to have solved this problem in Windows XP and 2003. In Windows 7 and 2008, this was actually causing a problem because the SYSTEM registry contains a setting "USERNAME=SYSTEM" by default that was overwriting the USERNAME when run as specific user. It was decided to disable this registry loading for Windows versions starting with XP and 2003. Of the supported versions, only 2000 is now reloading its environment. The only difference from version 3.5.4 and earlier that could be found is that when running as the SYSTEM user on Windows 7 or 2008, the USERNAME environment variable will now be set to the host name followed by a dollar sign rather than SYSTEM. This is actually how all other services work. But just in case this is a problem, it can we resolved by adding a "set.USERNAME=SYSTEM" property into the Wrapper configuration file. Bug #3061490. * (Standard, Professional) Fix a problem for Solaris and HP-UX where the socket timeout properties for the email notifications were ignored. * (Standard, Professional) Added wrapper.ntservice.recovery. properties to define system level actions in the event that the Wrapper process itself has a failure. * (Standard, Professional) Fixed a problem in the WrapperProcess.waitFor() and WrapperProcess.exitValue() call, where it would fail to return when called after the Wrapper had initiated the shutdown of the JVM. * (Standard, Professional) Add WrapperProcessConfig.setSoftShutdownTimeout(int) method to tell the Wrapper how long to wait after nicely asking the child process to shutdown cleanly when calling WrapperProcess.destroy(). Once the timeout has ellapsed, the child process will be forcibly terminated. This timeout had been hard coded to 5 seconds in earlier versions. * Add more detailed usage output to the UNIX shell script. * Make it possible to 'pause' and 'resume' the JVM from the UNIX shell and Windows batch scripts. * (Professional) Fix a minor memory memory leak while initializing timers. * Fix a memory leak which could happen if there were any invalid strings in localization resources. * (Professional) Fix a bug where the wrapper.event..command.argv. properties were not correctly parsed on Windows. This issue was introduced in version 3.5.0. * (Professional) Add the ability to define wrapper.event.default.command.argv. properties that will be used if the event specific specific commands are not defined. Mainly useful for testing. * Fix a problem occuring when the wrapper failed to roll the log file causing to write to the wrapper's default log (wrapper.log) file rather than continuing to write to the current logfile. * (Standard, Professional) Fix a put problem in the internal hash map implemenation used for localization where values could be lost. This was not a visible issue because of the data used. * Add new wrapper.filter.allow_wildcards. property and make it possible to specify wrapper.filter.trigger. patterns which contain '*' and '?' wildcards. * Add a commented alternative in the default OutOfMemoryError filter configuration to make it more specific to only trigger on uncaught exception stack traces. This is to avoid output like that from the -XX:+PrintClassHistogram JVM argument from causing the JVM to restart with a false out of memory warning. See the wrapper.filter.trigger. OutOfMemoryError example for more details. * Localize the default filter message. * Added ISO-8859-* encoding support and a few other encodings. * (Standard, Professional) Fix a problem on UNIX versions, parsing dates in license keys that was introduced in version 3.5.0. Windows verisons did not have this problem. All license upgrade terms and lease terms which contained "08" or "09" as either a month or day were being parsed incorrectly. This was leading the Wrapper to interpret those date components as "00". If the number was the date, then this would cause the date to be set to the last day of the previous month. If it was the month however, it would cause the date to be set to December of the previous year. For example "2010-08-20" was being interpreted as "2009-12-20", and "2010-10-08" was being interpreted as "2009-09-30". This would have prevented some licenses from being able to start because the upgrade terms were in effect prior to the Wrapper's release date. Some trial licenses could also have stopped early because their lease term end was earlier that it should may have been. For normal licenses, his will have no effect on installations once they are up and running because they do not use the lease term. * Fix a problem on Windows when a service received several service control codes in rapid succession. Since version 3.5.1, the Wrapper was only to process a single control code in each cycle of its main loop. This was resulting in messages like "Previous control code (4) was still in queue, overwriting with (4)." in the logs. The Wrapper can now handle up to 25 control codes per 10ms cycle. * Fix a problem where it was not possible to send passthrough arguments to the JVM when installing or updating a Windows Service. Passthrough using the "--" argument was added in 3.5.2. * Add a new wrapper.pause_on_startup property which makes it possible to tell the Wrapper to go directly into a paused state without ever launching a JVM. * Fix a problem where the STOP command set in a command file was being ignored if the Wrapper was currently in a paused state. * Make it possible to specify DEFAULT for the configuration file encoding. This will cause the file to be loaded using the default system encoding. We added this by request, but recommend using a portable encoding like UTF-8 to ensure that the configuration file will load correctly on all systems. * Added a WRAPPER_LANG environment variable which makes it possible to reference the current locale language code in the configuration file. One common use is to do localization using inclues. (e.g. #include ../conf/wrapper-%WRAPPER_LANG%.conf) 3.5.4 * Add optional support for custom public static methods in the WrapperSimpleApp and WrapperStartStopApp helper classes. Feature Request #2812276. * Add a new special configuration file directive "#properties.debug" which enables debug output about the properties as they are loaded by the configuration file. This can be useful to tell if and why certain properties are being overwritten. Feature Request #3042959. * Fix a minor problem where the "#include.debug" configuration file directive was sticky so it would be enabled when the configuration file was reloaded even if the reloaded configuration file no longer had the directive set. This was only an issue if the wrapper.restart.reload_configuration property was set. * Messages about missing included configuration files that were output when the #include.debug" configuration file directive was active were being logged at the ERROR level even though they were not problems. * Fix a minor problem where the WRAPPER_JAVA_HOME environment variable was not correctly being set to final when it was set internally by Wrapper. This could lead to unexected results if the user overwrote it later in their configuration file. * Fix a problem on AIX and z/OS, when running the Wrapper without any arguments. The Wrapper was attempting to use the default wrapper.conf file but the check for the file was failing causing the Wrapper to continue even though the file did not exist. This caused a confusing error message to be displayed, but was otherwise harmless. * Clean up some debug code associated with sleeping where log output was being queued when it did not need to be. * (Standard, Professional) Consolidate some redundant code associated with waiting for interfaces on startup. * (Professional) Fix a problem in the email feature of the Wrapper where a subject of more than 27 bytes in length when encoded as UTF-8. This was caused by a miscalculation in the Base64 conversion of the subject. * (Professional) Fix a problem when the WrapperManager.exec method which takes an array of command elements was called on Windows. The command elements need to be combined into a single command line, but if any of the elements contained spaces, the resulting command line was not being correctly quoted. * Add a new wrapper.java.command.resolve property to control whether or not the Wrapper tries to resolve any symbolic links in the Java command, specified with the wrapper.java.command property. Historically, it has always done so, but some jvm started applications like run-java-tool on Gentoo will fail if it is run directly as they have a check to make sure it is launched via a symbolic link. * Fix a problem on Windows versions where a path to the Wrapper binary, including the Wrapper binary itself, which was more than 100 characters would cause a buffer overflow when installing the service. A second similar problem would happen if the same path was more than 128 characters, whenever the Wrapper was launched. These were both very old issues and only happened on 32-bit versions of Windows XP and 2000. Microsoft documentation says that the issue should also exist on the 64-bit versions, but we were unable to reproduce it there. Newer versions of Windows are all fine. 3.5.3 * Fix a typo in the UNIX shell scripts that was causing "command not found" errors to be shown when running the Community Edition. * Add new wrapper.console.fatal_to_stderr, wrapper.console.error_to_stderr, and wrapper.console.warn_to_stderr properties to control whether the output at the FATAL, ERROR, and WARN log levels go to stdout or stderr. In the past they all went to stdout. With this change, FATAL and ERROR log levels now default to stderr output. * Fix a problem where the shell script would produce unexpected results if the Standard or Professional Edition shell scripts were used with the Community Edition Wrapper. Fix was in Wrapper binary by changing the default ERROR and FATAL log level console output to stderr rather than stdout. * (Standard, Professional) Fix a problem where script error message output was not being shown if the wrapper.conf file specified in the script did not exist. * Fix a problem where errors from failed forks on Windows were always being flushed immediately rather than honoring the value of the wrapper.console.flush property. * Fix a problem on Windows 2000 systems where a new feature added in 3.5.2 was preventing the Wrapper from running because the API used was too new. * Change the font of the wrapperw dialog in order to have prettier output of multibyte characters. * Add a line feed after the first message when starting the Wrapper from the UNIX script. * Add a note in the debug output so the configured java temporary directory is always logged to help with debugging. * Add a workaround for a bug in both Sun and IBM JVMs which cause an invalid exception to be thrown when a socket is already bound. It had been causing the Wrapper to report: "Unexpected exception opening backend socket: java.net.SocketException: Unrecognized Windows Sockets error: 0: JVM_Bind": http://bugs.sun.com/view_bug.do?bug_id=6965962 * Add the encoding of the subjects in the event mails to be always UTF-8 Base-64 encoded. * Add new wrapper.event..email.smtp.auth.type, wrapper.event..email.smtp.auth.userid, and wrapper.event..email.smtp.auth.password properties which make it possible to do LOGIN and PLAIN connection authorizations. Currently SSL (STARTTLS) connections to the mail are server are not yet supported. * Fix a buffer overflow while loading the configuration file on Mac OSX versions. Introduced in 3.5.0. * Fix a several memory leaks on UNIX versions that were added in 3.5.0, as well as a few others on all platforms, some from quite early versions. * Fix some places where a resolved path of exactly MAX_PATH characters in length could have resulted in a buffer overflow. * (Standard, Professional) Fix a memory leak disposing language packs. * Go through and increase the consistency of text strings. * Fix a problem on HP-UX where the Wrapper was logging a warning that the configured JVM was invalid if it was a PA-RISC 2.0 binary. Bug #3037317. * Fix a problem where the WrapperManager was failing to trap and hide errors initializing the MBean server on some JVMs that did not support it. 3.5.2 * Added new command line argument "--" . All arguments following will be preceded and passed to the java application. The arguments are attached after the arguments used in wrapper.app.parameter. * Fixed a problem in the shell script which could lead to report failed starts of a daemon incorrectly on the command line. * Implemented some small logic in the wrapper script which tries to change the permissions of the wrapper binary to executable if it wasn't set. * The Demo Application had problems locating the right conf file on Unix platforms and failed to launch the internal demonstration wrapper process. * Improved the error message logged if the Windows version of the Wrapper exits with an internal error. It now logs more information about the internal state of the Wrapper as well as saving a mini dump file which can be sent to support to make it easier to diagnose the cause of the problem. * Fix a problem where the names and displayNames in WrapperWin32Service instances were corrupted. List affected the WrapperManager.listServices() and WrapperManager.sendServiceControlCode() methods. There was a similar problem with the WrapperManger.getUser(), WrapperManager.getInteractiveUser() and WrapperManager.setConsoleTitle() methods. Introduced in 3.5.0. * Fix a problem on Windows where wildcards would sometimes fail to be resolved or cause the Wrapper to crash. This affected the generation of classpaths and logfile rolling. Introduced in 3.5.0. * Fix a problem on UNIX platforms where some error messages related to a failed fork to launch the JVM were not being logged correctly. Introduced in 3.5.0. * Fix a problem where invalid characters in configuration files that did not declare an encoding could cause the Wrapper to crash on startup. This could be issue for users upgrading from versions prior to 3.5.0 as older versions did not do any character set translations and would not have had a problem. * Fix a problem in code to check whether a drive was a mapped network drive or not was failing. This would sometimes lead to a false warning that the drive could not be identified. Introduced in 3.5.0. * Add a new ACCESS_VIOLATION command to the wrapper.commandfile property to test how the Wrapper and external systems behave if the Wrapper were to crash. Only enabled when the wrapper.commandfile.enable_tests property is enabled. 3.5.1 * Start using a system function to determine whether or not a character in the configuration file is a control character or not. This way it works on non-ASCII platforms. * (Standard, Professional) Fix a crash on Windows platforms caused by freeing up unallocated memory while loading the Wrapper's configuration. * Add debug output describing the system and current code pages on Windows versions to help understand encoding and mojibake issues. * Add a Japanese localized src/conf/wrapper.conf.in_ja template configuration file to assist Japanese users. * Fix an potential deadlock on UNIX platforms if the JVM exits while logging is taking place and the wrapper.debug or undocumented wrapper.state_output properties were set to TRUE. * Fix a problem where a failed JVM invocation that happened immediately after being launched would cause the Wrapper to immediately give up and shutdown. This should not have been possible with normal JVM configurations, but was turned up in testing. * Fix a problem where some startup output of the tick timer debug output was corrupted. This was only an issue if the wrapper.tick_output property was set. * (Standard, Professional) Rework the way text is localized so that mallocs are all handled on initialization. 3.5.0 had problems with occassional freezes and crashes caused by mallocs being made within signal handlers. The problems were rare unless debug output was enabled. * Greatly simplify signal handlers on all platforms so they now do as little as possible, actions are now queued and then processed by the main thread. * (Standard, Professional) Fix a problem where the hostname in the wrapper.syslog.remote.host couldn't resolve a hostname (IP Address was working). * (Standard, Professional) Add debug output on Windows versions to help debug localization and code page issues. * (Standard, Professional) Fix a localization problem on Windows where the Wrapper was using the system-wide language rather than that of the current process. This was resulting in mojibake if the Wrapper was launched in a new console if that new console did not support the required code page. This was only an issue if the user had changed the active code page from the default for their Windows desktop. * Fix a problem on Windows platforms where the JVM child output was being logged with an extra line feed in some cases. * Fix a problem running the DemoApp from some Network shares on Windows. * Add a new WrapperManager.isWindows() and WrapperManager.isMacOSX() methods to make it easy to write such conditional code as both platforms can require non standard code. * (Standard, Professional) Make the GetHostId.bat file more robust so it can be executed using a relative reference from the command line. It also now supports Delta-pack style Wrapper binary naming and falling back to use which binaries are available. * Change the timing of when the wrapper.working.dir is set so that any error messages generated while loading the configuration will be logged to the correct log file. It is also needed for Standard and Professional Editions to ensure that the language pack is loaded from the correct location so that all such messages will be in the correct locale. * Fix a problem on UNIX platforms where the status command was failing with an error due to the localization feature added in 3.5.0. 3.5.0 * (Standard) Added the ability to detect and react to thread dead locks in the JVM. Requires at Java 1.5. Added wrapper.check.deadlock, wrapper.check.deadlock.interval, wrapper.check.deadlock.action, and wrapper.check.deadlock.output properties to configure the detection. * (Professional) Add a new jvm_deadlock event which is fired in response to a thread deadlock being detected within the JVM. * Fix a problem where the intervals like wrapper.ping.interval were all rounding down causing them to function at a rate one second shorter than configured. * Fix a minor memory leak calling WrapperManager.exec. * Add a new wrapper.filter.message. property which can be used to control the message which is logged when a wrapper.filter.trigger. is matched. * Rework the way actions are fired for the wrapper.filter..action and wrapper.timer..action properties so there is no longer any duplicate code. * Modify the way the wrapper.filter..action and wrapper.timer..action properties work so it is now possible to specify a list of actions which will happen in the order specified. This makes it possible to do a thread dump and then restart in response to an error. * Add the DEBUG action to the wrapper.filter..action property for consistency. * (Professional) Implement the ability to fire user defined events as actions of the wrapper.filter..action, wrapper.timer..action, and wrapper.check.deadlock.action properties. * Fix a problem in the WrapperProcess.destroy() function, when a child process couldn't have been forcibly killed. * Add GetHosdID.bat file for Windows platforms. This file will open a dialog displaying the HostId of the machine. * Fix a problem in the shell script which, on a rc based OS, could lead to problems starting the Wrapper when the APP_NAME in the script contained capital letters. * (Standard, Professional) Added a set of wrapper.share..* properties which makes it possible to configure the Wrapper to map specific network resources before launching the JVM on Windows. * Corrected the way the Wrapper is installing itself as a Windows service when the binary and/or conf file are located on a Mapped Drive. * Add new wrapper.pausable and wrapper.pausable.stop_jvm properties to control whether the JVM can be paused or not, and deprecate the use of the Windows specific wrapper.ntservice.pausable and wrapper.ntservice.pausable.stop_jvm properties. * Modified the wrapper.commandfile property so PAUSE and RESUME commands are now supported on all platforms at any time. * Modified the wrapper.filter.action. property so PAUSE, RESUME, and DEBUG actions are now supported. * (Professional) Modified the wrapper.timer..action property so PAUSE and RESUME actions are now supported. * (Professional) Modified the wrapper.event..command.block.action property so PAUSE and RESUME actions are now supported. * Added new WrapperServicePauseEvent and WrapperServiceResumeEvent classes to make it possible to notify an application that it has been paused or resumed. To date, this was only possible when the Windows service was paused or resumed * (Professional) Add new "wrapper_pause" and "wrapper_resume" event types that are fired whenever the Wrapper is paused or resumed. * Enhance the command line parsing for the WrapperManager.exec() command. The single commandLine version of the exec call will handle quotes more sophisticated. * Modified the wrapper.syslog.ident property so its value is now silently trimmed to 32 characters in length. This is needed to avoid problems with syslog servers. (See RFC 3164 section 4.1.3) * (Standard, Professional) Add new wrapper.syslog.remote.host, wrapper.syslog.remote.port, and wrapper.syslog.local.host properties which can be used to redirect all syslog (UNIX) or Event Log (Windows) output to a remote syslog server. * Add support for the wrapper.syslog.facility property on Windows so remote syslog entries can be sent from Windows versions of the Wrapper. * Add debug output from the WrapperManager class which shows information about the current wrapper.jar, including its size, location, and MD5 hash. * Add a check for wrapper.java.classpath. entries containing quotes. The quotes are now stripped and a debug warning logged. * (Standard, Professional) Increase the size of the wrapperw.exe error dialog so it is a little easier to read. Also changed the font for the same reason. * (Standard, Professional) Modify the title of the wrapperw.exe error dialog so it now includes the value of the wrapper.displayname property. * Add a new check for the writability of the configured Java temporary directory. When running on Vista, it will not be writable and can lead to errors. * Added new wrapper.java.tmpdir.required and wrapper.java.tmpdir.warn_silently properties to control whether the temporary directory is required. * Add a note in Wrapper conf template showing users how to configure a specific Java version to use. * Add a new CLOSE_SOCKET command to the wrapper.commandfile property and added a new wrapper.commandfile.enable_tests property to control whether it can be used. * Fix a debug warning while shutting down caused by one thread closing the backend socket when another expected it to be open. * If the backend socket between the JVM and Wrapper is somehow closed, make the JVM respond promptly by restarting the JVM immediately to resync with the Wrapper. Added log information to make it clear when this happens. * Add a new wrapper.use_tick_mutex property to control whether or not the internal tick timer is protected by a mutex. (Experimental) * (Standard, Professional) Add support for zLinux 32 and 64-bit on s390 and s390x systems. * Change the internal encoding of the wrapper from native characters to UNICODE. This will allow the wrapper to handle correctly any characters in its configuration file and internally. * (Standard, Professional) Implement a new WrapperResources class which makes it possible for user applications to localize their applications using the same methods common to native applications. The Wrapper uses this internally to provide localized versions of the Wrapper. * Remove the old org.tanukisoftware.wrapper.resources package as it is no longer being used. * (Standard, Professional) Add Japanese language pack to localize the Wrapper to Japanese. * Fix a problem in the WrapperManager class where unexpected exceptions thrown in the main socket loop were being thrown away without being logged. * Make the Wrapper more robust against failures removing the Wrapper's shutdown hook on shutdown. It had been causing the clean shutdown of the JVM to fail as an unexpected exit. * Fixed a problem in the wrapper customize code where customized multi layer icons may get scaled incorrectly by Windows. Bug #3015848 * Modify the wrapper.on_exit. property so it is now possible to PAUSE the Wrapper when a JVM exits. This delays the restart of the JVM until the Wrapper is resumed. * Add a new log format, 'U', which logs the approximate time in seconds since the Wrapper was launched. It is based on the internal tick timer and will be a few percent lower than the actual number of seconds that have elapsed. Added to the wrapper.console.format, wrapper.logfile.format, and wrapper.logdialog.format properties. * Fix a problem where deleting the configured anchor file was not recognized if the JVM was not running at the time. The Wrapper was not noticing that it was missing until the next JVM was launched. * (Standard, Professional) Add a new NOTICE log level which is used to log license related message. These will only show up trial license log output. * (Standard, Professional) Add a new default 15 minute trial license which can be used out of the box on any machine without the need to register and obtain a trial license or purchase a license. * Add a new wrapper.environment.dump property which will dump all of the environment variables to the log, along with where the variables originated. * Force the Wrapper to flush all logfile output for each line until the configuration file has been loaded. There is normally no output up to this point anyway, but this ensures that any errors are logged in a consistent location. * Move the registration of the main thread with the logging system up a bit to make it possible to perform low level debug logging earlier. * Add a set of checks to display an error and prevent the Wrapper from starting if the batch or shell scripts being used are based on the TestWrapper demo application. It is important that the user start with the default template files in the distribution src/bin and src/conf directories to make sure the integration goes smoothly. 3.4.1 * Fix a problem where the wrapper.app.parameter.1 property was always being set to an empty string when launched from launchd on Mac OSX. It worked correctly with the testwrapper application, but would fail for most user applications. * (Professional) Fix a potential synchronization problem in the log output of the tick timer, event command and event email code. This had been in the code since 3.3.0 without any reports of problems. * Improve the error message displayed when the configured wrapper.java.command can not be found on the path. * Log the name of the signal in the logs when a SIGSEGV is detected from the JVM. It had been logged as Unknown. * Add some comments to the wrapper.conf.in template to help users get started with a new license key file. * Add some default properties to the wrapper.conf.in template file to make it easier to get up and running with out of memory checks, as well as sending out alert emails. * Add a small debug message when running wrapperw.exe so it is clear which wrapper binary is being used. * Fix a problem where the wrapper.logfile.maxfiles was not being applied on startup when the current log file did not yet exist. This was true for any wrapper.logfile value which contained a unique value like a PID. * (Professional) Fix a problem in the WrapperProcess.destroy() function, where the function was failing to forcibly kill the child process. * (Standard, Professional) Add a new GetHostID.bat file for Windows platforms. This file will open a dialog displaying the HostId of the machine to help new users get up and running. * Add a new WrapperManager.appearOrphan() method which can be used to test how the WrapperManager shuts down the JVM in the event that the Wrapper process ever crashes or freezes. This was not due to any particular problem and was added to fill out our test coverage. * (Professional) Fix a problem where event commands were being left in a defunct state after execution on UNIX platforms. * Fix a potential problem on 64-bit versions where the internal tick timer was not rolling over in the same way as the 32-bit versions. This has been in all previous versions but is not known to have caused any problems. It was fixed for consistency. * Modify the WrapperManager class so it will now request a JVM hard exit only after 4-times the ping timeout, in seconds, since the last contact with the JVM. This had been 90 seconds more than the ping timeout, which was not always long enough when the wrapper.ping.timeout was very large. * Shift the initial start point of the tick counter so it will roll over 50 seconds after startup. This shouldn't be noticeable to the user, but makes sure that this roll over is much better tested as it always happens the first time on startup. * Add a new wrapper.java.classpath.use_environment property which makes it possible to set the classpath using the CLASSPATH environment variable rather than including it on the Java command line. * Fix a problem where requests to shutdown the Wrapper when in the state where it was just about to launch a JVM would being ignored. This was fixed in all editions, but was only an issue in the Professional Edition when the wrapper.event.jvm_prelaunch.command.on_exit.=SHUTDOWN property was being used with the wrapper.event.jvm_prelaunch.command.block=TRUE property and the command exited with a code that triggered the SHUTDOWN. * (Professional) Add a new wrapper.event..command.block.action property to control how the Wrapper behaves when a command does not complete execution within the configured timeout. Accepted values are CONTINUE, KILL, KILL_SHUTDOWN and KILL_RESTART. Default value is CONTINUE. * (Professional) Made it possible to use the "default" event type with the wrapper.event..command.loglevel, wrapper.event..command.block, wrapper.event..command.block.timeout, wrapper.event..command.on_exit., and wrapper.event..command.on_exit.default properties. * Fixed a single byte buffer overflow which takes place just before the JVM is launched on Windows platforms. This was introduced in 3.4.0. * Add a message pointing the user to the Wrapper's log file when the service fails to start after it has been launched. * Update the debug message displayed when attempting to open the backend socket if the port is unavailable so it doesn't seem like a problem. It will retry with another port. * Work around an issue on some Solaris problems where the shell script would fail if /usr/ucb/ps wasn't installed. * Fix a problem on UNIX versions where the Wrapper would fail to resolve the correct location of java if it was located using the system PATH, and that PATH element pointed to a binary via a relative symbolic link. This was introduced in 3.4.0. 3.4.0 * Increased the minimum supported Java version from 1.2 to 1.4. * Removed the reflection code used to manage the Wrapper's shutdown hook. The Runtime methods are now called normally. * Add a note in the TestWrapper shell script to make it clear that the user should always use the scripts in the WRAPPER_HOME/src/bin/ directory when generating scripts for their own applications. This became more of an issue because of changes to the TestWrapper script starting with 3.3.8. Bug #2902843. * (Professional) Added new WrapperManager.exec methods and a new WrapperProcess class to allow the launching and management of child processes through the Wrapper rather than using the standard Runtime class. This makes it possible to clean up child processes when the JVM crashes or is restarted, as well as solves severe memory issues with the way processes are forked on some UNIX platforms. * (Professional) Added a new wrapper.child.status.loglevel property to make it easier to debug the status of child processes. * (Professional) Added a new wrapper.child.count.interval property to control the interval at which the number of waiting child processes is logged after a JVM is shutdown. * (Professional) Added a new wrapper.jvm_cleanup.timeout property to control the amount of time that managed child processes still running after the JVM has exited are given to shutdown before being forcibly killed. * Fix a problem with WrapperManager.getUser() and getInteractiveUser() methods which was preventing us from using the latest compiler on 32-bit Windows. (The compiler used to build 32-bit Windows versions was rolled back to the version used through the 3.3.5 release in 3.3.9 to work around the problem that was causing these methods to always return null.) The change in this version should not affect how the Wrapper functions. * The old compiler used in 3.3.9 for Windows 32-bit builds was causing a false hit on Symantec security software. The new compiler causes the Wrapper to once again pass without any warnings. * Added a warning while starting up the JVM which will be displayed if the Java command in wrapper.java.command does not point to a valid java binary file. * [Changed the scripts and batch files to try to load the wrapper executable according to the system, i.e. on 64-bit systems the 64bit binary of the wrapper is attempted to be executed first and after this fails the 32 bit gets attempted to be loaded. This behaviour is primaly useful with the delta-pack of the wrapper.] * Add some debug output logging the current timezone to assist supporting time related problems. * (Standard, Professional) Added a new wrapper.license.debug property which will log information about the license key(s) being tested on startup. * (Standard, Professional) Fix a problem where license validation was failing at certain times of the day for servers with timezones east of Japan. Development license keys which have their update times obfuscated were not affected. This was a problem introduced in 3.3.7. * Fixed a bug in the wrapper shell script which occured when running the script on a Solaris within a non singlebyte locale. Bug #2910327 * Fixed a potential bug in the wrapper script where requesting a Thread Dump, the shell is sending the wrapper console to the background and returning with a prompt. * Fix a problem where Java log output would sometimes get extra line feeds when under heavy load. * Fix a problem which was leading to a resource not found error when trying to start a service, if it was installed on a Mapped Network Drive under Windows. * Added some advice messages recommending the use of UNC paths if a resource located on a Mapped Network Drive is used in the configuration file on Windows versions. * (Standard, Professional) Fix a bug in the wrapper binary customization, which occured when the source binary file was set to read only. * Fixed a null string problem in the error message if a classpath value wasn't found. * (Professional) Added the option to include a logfile into the wrapper's EmailNotification mails via wrapper.event.default.attach_log=TRUE * Improve the message displayed when a user calls WrapperManager.requestThreadDump() in JVM which does not have console window on Windows. This should never be an issue when run with the Wrapper, but can happen if running standalone without the wrapper binary. * Update the Windows batch scripts so they now take AMD64 and IA64 architectures into account when deciding which version of the Wrapper to run when using the delta pack. * Update the UNIX shell script so it now does a much better job of resolving the ideal platform bits to run the correct version of the Wrapper when using the delta pack. Thanks to Leo Leung for the patch. * Add install and remove commands to the UNIX shell script so it is now much easier to install and remove the Wrapper on many UNIX plattforms to start and stop on system startup and shutdown. Thanks to Leo Leung for the patch. * Update the Windows batch scripts so it is now easier to change the location of the Wrapper configuration file or rename the Wrapper binary when using the scripts. * Added a new QueryApp-NT.bat.in template script which can be used to query the current running status of the service on Windows. * (Standard, Professional) Add a new "-u" or "--update" command to the Wrapper which allows you to effectively reinstall the Wrapper as a service without having to provide the account credentials if the service is running as a specific user. This is very useful for installers upgrading an application to a new version. * Add a new "update" command to the Windows AppCommand.bat.in batch script. * Go through and clean up the messages displayed when controlling the Wrapper as a service so the messages are consistent and more meaningful to the user. * Add wrapper.wait_for_hostid and wrapper.max_hostid_timeout property. This properties set if and how long the wrapper shall wait when starting up until the hostid is available. This is important to make sure that server licenses are validated correctly on UNIX platforms as the OS is booting up. * (Professional) Fix a problem where environment variables referenced in property values were not being expanded correctly the first time they were referenced if the property's value was a default value. The underlying fix was in all editions, but this was only causing a problem in the Professional Edition where the WRAPPER_HOSTNAME variable was not being expanded in the subject and body of emails sent out for the "wrapper_start" event if the defaults were used. * (Professional) Fix a problem where backslashes in the body of emails, configured with the wrapper.event..email.body property, were not being handled correctly when displaying things like paths from environment variable references. * Fix a problem on UNIX platforms where the Wrapper was displaying an error about not being able to locate the configuration file when the Wrapper was run without any arguments. * (Standard, Professional) Improve the message shown when a License Key is not found. * Add a new message to the Community Edition when the user requests a HostId. * Add WAIT_FOR_STARTED_STATUS and WAIT_FOR_STARTED_TIMEOUT to the script. This lets the script wait (up to timeout sec.) when starting a daemonized process until the process has been started. Thanks to Dobes V. Feature Requests #2917391. * Improve the error message displayed when the user tries to run the Wrapper with the internal -s or --service commands. * Fix a problem where the WrapperSystemPropertyUtil.getBooleanValue() method was not correctly returning the specified default value when the looked up property was missing. Also added a new getStringValue() method. * Improve the error message displayed when the user tries to install and remove the wrapper as Service on Windows Versions after Windows Vista. * Add an advice message when MacOSX applications launched with launchd encounter a "Returning nil _server" error when displaying a GUI. 3.3.9 * Modify the way JNI functions are called from within the native library so they work correctly on platforms which are not ASCII based. * (Professional) Add support for IBM z/OS 390 servers. This is still an alpha release and will be made available on request. * Improve the message displayed when a server license key is used on a different server. * Add a minimum max file size of 1024 bytes to the wrapper.logfile.maxsize property to avoid the log file rotating too often if the user enters a very small value. * Add a message that shows up in the console when the Wrapper fails to write to the configured log file. As with previous versions, it will then fall back to writing to wrapper.log in the current working directory. * On UNIX platforms, automatically set the wrapper.disable_console_input property when wrapper.daemonize is set. * Fix a problem introduced in 3.3.8 where relative configuration file includes were failing to resolve correctly when the wrapper.working.dir and wrapper.daemonize properties were used together. The wrapper.daemonize property causes the configuration to be loaded twice on startup and the working directly was not being reset correctly before it was loaded the second time. * Fix a problem introduced in 3.3.8 where wildcard selection of files on Windows failed in some cases. * Fix a problem introduced in 3.3.8 where setting the wrapper.logfile.maxfiles property to 0 was causing all log files to be deleted rather than none when the ROLLNUM file pattern was used. * Revert the way rolled log files are deleted when using the ROLLNUM file pattern to the functionality used in versions 3.3.7 and earlier. Files such as wrapper.log.bak or other files manually created with the same log file base name were also being deleted with 3.3.8. * (Standard, Professional) Fix a problem where the close window button in the title of the WrapperW log dialog was not correctly cancelling the dialog. * (Standard, Professional) Fix a problem where the WrapperW log dialog would sometimes fail to show itself on top of other windows if the splashscreen had been displayed on startup. * Fix a problem on 32-bit Windows versions where starting with he Wrapper, the WrapperManager.getUser() and getInteractiveUser() methods were always returning null. This problem was introduced in version 3.3.6. * (Professional) Fix a buffer overflow when sending alert emails to multiple addresses. This would sometimes cause crashes in versions 3.3.7 and 3.3.8 when sending alert emails to even a single recipient. Because of the nature of the overflow, in most cases did not cause any problems. 3.3.8 * Add the new start type DELAY_START for NT Services, which startes the service after other auto-start services are started plus a short delay. * Fix a problem where the Wrapper's PID file was not being set to the correct PID when the wrapper was launched daemonized. With the shell scripts that ship with the Wrapper, this means that it would not be possible to stop the Wrapper using the script because the expected PID did not exist. This was a problem introduced in 3.3.7. * Changed the timing for the wrapper's splashscreen when the splash screen mode was set to JVM_STARTING. Now the splashscreen will disappear when the JVM has been initialized. * Fix a problem where the splashscreen was being shown when starting a service or performing other command line operations. * Remove some extra debug output on startup for Mac versions. * Fix a crash in the Community Edition on PPC platforms of the Mac OSX version. This crash has been reproduced in all versions starting with 3.3.1. The OSX distribution is a universal binary but does not appear to result in a crash on x86 servers. Standard and Professional Editions were not affected. * Fix a problem on Windows versions where problems accessing the registry were not reporting the correct error message. This did not cause any problems in and of itself, but it made it difficult to track the down the cause. * When wildcards are used in the classpath elements, the list of matching jar files included in the classpath are now sorted to ensure that their order is consistent across installations. Normally it would not matter, but if certain classes or resources are redefined in multiple jars this will ensure that the application now always works the same. * Fix a problem where wrapper.logfile.maxfiles was being ignored when wrapper.logfile.rollmode=JVM was set. * Changed the way the wrapper.logfile.maxfiles property works with the ROLLNUM token. Now when the log files are rolled, all files greater than maxfiles count will be deleted. Previously, the Wrapper would roll within the maxfiles count and ignore extra files if they existed. This would cause extra files to be left around if the maxfiles property value was decreased. * Add new wrapper.logfile.purge.pattern and wrapper.logfile.purge.sort properties which make it possible to limit the number of log files in some advanced cases. Be sure to read the documentation before playing with them. * Fix a potential crash when referencing non-existent environment variables in the value of wrapper.logfile. * Modify the way all properties used to define file names behave so that undefined environment variable references will now have their '%' characters replaced by '_'. This is to avoid problems caused by file names containing '%' characters on some platforms. * Fix a problem introduced in 3.3.6 where the windows shown by the JVM or its child processes could not be displayed when running in iteractive mode. * Rework the TestWrapper application a bit so it can now be run in headless mode for testing. * Fix a problem on some UNIX platforms where the shell script was showing an extra '-n' when run with the "start" command. * Fix a problem for FreeBSD which could cause the wrapper being unable to stop the wrapper daemon if the ps command buffer size (kern.ps_arg_cache_limit) was too small to contain the wrapper command line. 3.3.7 * (Professional and Standard) Added the ability to customize the wrapper.exe and wrapperw.exe binaries on Windows with a user specified icon and splash screen. * (Professional and Standard) Added a new wrapper.splashscreen.mode property to control how long the splashscreen is visible. * Fix a problem on SELinux where a strict security policy could lead the Wrapper fail to load the libwrapper library. Thanks to Jean for the hint. * Fixed a problem in the obfuscated license date, which caused a license to be reported as invalid if run in a timezone west of Japan. This feature was implemented in 3.3.6, but disabled on the site until the release of version 3.3.7. Thanks to Leo for the hint. * Added a new WRAPPER_PID environment variable. Feature Request #2870136. * Added a new WrapperManager.getWrapperLogFile() method and WrapperLogFileChangedEvent class that can be used to receive notifications of changes to the Wrapper log file currently in use. Feature Request #2870133. * (Profesional) Improved the wrapper.event..email.to property so it now supports the ability to specify multiple recipients. 3.3.6 * Introduce the wrapper.timezone property. This property allows to set the timezone in which the wrapper will be executed. This property is available in the standard and the professional Edition of the Java Service Wrapper. * Fix a potential problem on Windows platforms where a failure to register the control handler was not being logged. If this happened, user logoffs would not be trapped correctly but no other problems would have occurred. * Fixed a problem in the shell script on Solaris platforms where a deep directory structure would cause the script to incorrectly report that the Wrapper was not running. That could lead to multiple zombie copies of the Wrapper and its application running in memory. Bug #1664303. * Fixed a problem in the shell script on HP-UX platforms where a deep directory structure would cause the script to incorrectly report that the Wrapper was not running. That could lead to multiple zombie copies of the Wrapper and its application running in memory. Bug #2812207. * Improve the error message displayed when there are problems initializing the main class specified for the WrapperSimpleApp, WrapperStartStopApp, or WrapperJarApp helper classes. * (Professional) Add new wrapper.event..loglevel and wrapper.event..message properties which can be used to output a customizable message like "Event: " to the logs at an arbitrary log level. * Add debug output in the Windows version to log the full path of the native library. * Add a new wrapper.java.detect_debug_jvm property which will control whether or not the Wrapper disabled timeouts when java's debugger is in use. The Wrapper has automatically disabled timeouts in this case since version 3.2.1. Thanks to Ruslan Gainutdinov for the patch. * Fix a buffer overflow problem for values of wrapper.ntservice.name. * Fix a problem with where the wrapper.syslog.ident property was not working as documented. It had been necessary to use wrapper.ntservice.name in its place. * Add a new wrapper.ignore_sequence_gaps property which makes it possible to have non sequential numbered property values. This affects the wrapper.app.parameter., wrapper.event..command.argv., wrapper.filter.trigger., wrapper.java.additional., wrapper.java.classpath., wrapper.java.library.path., wrapper.ntservice.dependency., and wrapper.timer..interval, properties. The default value maintains past functionality. Feature Request #1930298. * (Professional) Fix a problem where the Event Handler Variables were not being set correctly in the values of the wrapper.event..command.argv. properties. * (Professional) Fix a potential access violation if memory allocations fail while sending event mails or executing event commands. * Add a new WRAPPER_HOSTNAME default environment variable as an alias of the existing WRAPPER_HOST_NAME variable. * (Professional) Deprecate the use of the wrapper.event..set_environment property. It will remain in the product for compatibility but its use is discouraged as it does not always work correctly when the configuration file is reloaded. See the property's documentation for more details. * Add a new DUMP action to the wrapper.filter.action. property to make it possible to invoke a thread dump in response to a specific string in the JVM's console output. * Fix a problem where the WrapperManager.stopAndReturn method was dead locking if called when the JVM was being run in standalone mode without the Wrapper. Bug #2711872. * (Standard, Professional) Modify the way the licensing times work so the Wrapper compares the License Upgrade Term to an official release date rather than the build date. This makes it possible to release additional platforms at a later date while keeping the use of a license consistent. * (Standard, Professional) Make it possible to obfuscate the upgrade term in License Key files for development licenses so it is not visible to an end user what the development license holder's upgrade term is. This feature is accessed from the License Management Page when downloading a new or existing License Key file. 3.3.5 * Fix a problem on some UNIX platforms introduced in 3.3.4 where the Wrapper would crash on startup if the configured JVM could not be found. * Fix a problem introduced in 3.3.2 where the Wrapper could crash if the system host name was longer than 27 characters in length. * Fix a potential problem with the way thread ids were being compared on UNIX systems. * Add a new wrapper.java.additional.auto_bits property which will automatically add the -d32 or -d64 arguments to the JVM for platforms whose JVMs typically expect the argument. * (Professional) Fix a problem with the Date field of outgoing event emails. 3.3.4 * (Standard, Professional) Update the development license to version 1.1 so that a new copyright notice file can be shipped with user applications rather than the full license text. * The Community Edition may be licensed under either the GPL2 based Community License, or the Development License. The source for the Standard and Professional Editions of the Wrapper are proprietary. http://wrapper.tanukisoftware.org/doc/english/licenseOverview.html * Fix a problem introduced in 3.3.2 where querying a the status of a Windows service with the -q or -qs commands resulted in an access violation. The running status of the service was reported correctly but additional configuration information was failing. Bug #2644515. * Add a new wrapper.disable_restarts.automatic property to disable only restarts caused by JVM timeouts, crashes, etc. Manual or configured restarts will still be allowed. * Switch to using make for HPUX IA 32/64 builds. * Add Advice comments when the Wrapper fails to launch the JVM process. * Fix a problem on UNIX platforms where log entries made by the forked Wrapper process would result in two blocks of log entries in the log file because the parent Wrapper process would think they were console output from the JVM process. * Add a set of new wrapper environment variables that can be referenced in the wrapper.conf file to generate random numbers, or timestamps for use in generating unique file names, etc. See the Default Environment Variable definitions section for more details. * (Standard, Professional) Fix a problem with Development licenses being able to authorize applications using Integration Method #4 which was added in version 3.3.3. * Add the number of bits of the current Wrapper to the startup banner to aid in support requests. * (Standard, Professional) Fix a crash problem on HPUX versions which would reliably happen on some machines at startup. 3.3.3 * Modify the wrapper.ignore_signals property so it now takes the values WRAPPER, JAVA, and BOTH, in addition to TRUE and FALSE. * Modify the WrapperManager so it is now careful never to poll the native library once the JVM is flagged as being ready to shutdown. This is to make sure that the JVM never exits in the middle of a call as that could lead to the JVM crashing. * Add a pair of methods to allow threads to request and release locks which will prevent the Wrapper from letting the JVM exit while certain operations are in progress. See WrapperManager.requestShutdownLock() and WrapperManager.releaseShutdownLock(). * Fix a problem where interactive services would sometimes leave a console window visible when after starting up. The Wrapper is now more resilient about closing the window even if it fails to do so initially. * Add a new integration method (#4), which makes it easy to configure the Wrapper to execute an executable jar file. * Fix a problem where the random generator was not being seeded correctly before naming the Wrapper's console window when running as a Windows service. This was leading to problems identifying the wrapper's console when more than one service was running on the same machine. 3.3.2 * Add a file information record to the wrapper.exe and wrapperw.exe binaries so the Version tab will be displayed correctly in the Properties dialog of the file. * (Standard, Professional) Fix a problem with the wrapperw.exe binary where the log dialog was not being displayed correctly when the Wrapper was launched with the "-?", "-v", or "-h" arguments. * (Standard, Professional) Fix a problem with the wrapperw.exe binary where a message was being displayed in the dialog with the location of the full log file even if there had not been any entries written to the log. * (Professional) Improve the debug output produced when sending event emails when the wrapper.event..email.debug property enabled. * (Professional) Add wrapper.event..email.send.timeout and wrapper.event..email.receive.timeout properties to avoid the wrapper hanging waiting for a response from a remote mail server. Bug #2064885. * (Professional) Fix a problem where the Wrapper would get stuck and fail to send emails with some mail servers. Problems was being caused by incorrect linefeeds in the body of the email. * Add a warning if the leading '#' is missing from an '#include' in the configuration file to assist users with include file problems. * Added a new wrapper.ntservice.generate_console property which will cause the Wrapper to always generate a console when running as a service and then hide it immediately. This will cause a slight flicker but is needed to support thread dumps. Bug #2060181. * Fix a problem in the Windows version where the console window would sometimes be left visible when running as an interactive service even when it was configured to be hidden. * Add support for PowerEvents so Windows services can respond to suspend and resume events. * Fix a problem where the wrapper.key system property passed to the JVM was being generated incorrectly randomly, 1 in 2048 times the JVM was launched. This would result in the JVM failing to start and the Wrapper shutting down. * Add a new wrapper.disable_console_input to disable to feature which allows the Wrapper to pass console input on to the Java process. * Fix a buffer overflow problem in the logging code which would happen once on startup. This was benign on most platforms but was causing intermittent crashes in the 32-bit AIX version. * Modify the way configuration properties are parsed so that their names are no longer case sensitive. * Modify the WrapperServiceException so that a new getErrorCode method can be used to obtain the integer error code which caused the exception. Feature Request #2188280. * (Standard, Professional) Fix a problem where on some Windows machines the Wrapper would return a random hostId that changed each time the system was rebooted. * (Standard, Professional) Make it possible to define License Keys so that their property names are encoded using either the host name or hostId. This makes it possible to define multiple keys within the same configuration file, visible on the same host. This was necessary to support some load balanced network adapters where the visible hostId changes depending on the active physical network adapter. * Rework the Java side state engine so it is now possible for the Java side of the Wrapper to respond to stop events while the WrapperListener.start method is still in progress. * Add a new wrapper.listener.force_stop property which allows control over whether the WrapperListener.stop method is called on shutdown even if the WrapperListener.start method has not yet completed. * Fix a problem on Windows where the ability to start and stop the Wrapper as a service using the Wrapper itself was requiring the Administrator permission when a lower permission should have been possible. The Wrapper should now allow service control to do whatever is possible from the Services control panel. * Fix a memory corruption error if the value of wrapper.java.maxmemory was more than 4 digits in length. wrapper.java.initmemory did not have any problems. * (Professional) Add a new wrapper.event..email.client.host property which makes it possible to configure the host name sent in EHLO and HELO commands to the SMTP server. * Add a new default environment variable, WRAPPER_HOST_NAME, which stores the name of the machine where the Wrapper is running. 3.3.1 * Add debug output showing the current os name and architecture to aid in debugging problems. * (Standard, Professional) Improve the message displayed when a license key is found but is deemed to be invalid. * Modify the template wrapper.conf file to help users debug include file problems. * Disable the console title feature on all UNIX platforms other than LINUX because the console title does not get reset correctly when the Wrapper process terminates. * Add support for HP-UX IA64 CPUs. * Update the license banner in source files so it is clearer that the user is restricted by the license they agreed to. * Modify the Community edition so it will now display a Licensed to banner on startup if shipped with a Development License. This is required to enable the distribution of the Community Edition under the Development License. * (Professional) Fix a problem where the UNIX versions of the Professional Edition would sometimes deadlock on startup when run as a daemon process. Bug #1989355. * (Professional) Added two new events; jvm_failed_invocation and jvm_max_failed_invocations. Feature Request #1994718. * Fix a problem where the Windows service exit code was not being set correctly when the JVM exited with a non-zero exit code. The problem could be seen by running "sc query {service}" from the command line. Bug #1859061. * Added support for the Windows Itanium 64-bit platform. * Added support for the HP-UX Itanium 32 and 64-bit platforms. * Added support for the MAC OSX 64-bit platform. * (Standard, Professional) Fix a problem on Windows versions where servers which reported a large number of possible host ids could cause a buffer overflow on startup. This crash was possible when using either Development or Server licenses. Removed duplicate host ids from the list of possible ids. * Add a new "condrestart" command to the shell script which will restart the Wrapper only if it is already running. Feature Request #1928045. * Fix a problem where the 64-bit Solaris x86 version was unable to load its JNI library. Bug #1992039. * Fix a problem on Windows versions where a frozen JVM process was not always being killed. This could result in the zombie JVM processes being left around that consumed memory and other resources. * Add a new wrapper.ignore_console_logouts property which allows the Wrapper and JVM to survive logouts when launched as a console application from another service. * (Standard, Professional) Add a wrapperw.exe binary in Windows implementations which makes it possible to run the Wrapper without a console. A console still flickers for an instant when the Wrapper starts. This is the same issue that has existed when running as an interactive service and is required to make thread dumping possible. * (Standard, Professional) Add new wrapper.logdialog.enable, wrapper.logdialog.format, wrapper.logdialog.lines, and wrapper.logdialog.loglevel properties used to configure the display of a Log dialog when the wrapperw.exe binary exits in an error state. * Fix a problem where the Wrapper was attempting to reopen its backend port even when the JVM was down. This was only a problem when the defined port range was limited to a single port with the wrapper.port.min and wrapper.port.max properties. In such a case one or more warning messages were being displayed because the port is locked for a few moments after being closed. * (Standard, Professional) The wrapper.initmemory.percent and wrapper.maxmemory.percent properties were not correctly being calculated relative to a maximum of 2048MB for 32-bit versions of the Wrapper. Bug #2053167. 3.3.0 * Add a new wrapper.ping.interval.logged property which makes it possible to reduce the debug output caused by ping transactions between the Wrapper and JVM. * Fix a problem on Windows where the Windows Service Manager was not waiting the full configured time of the wrapper.jvm_exit.timeout and wrapper.shutdown.timeout properties. This was leading to the net stop command timing out and the system shutting down without the java application having fully stopped. Bug #1582568. * If internal firewalls were preventing the backend socket from being created, it was not being made clear what the cause was. It was also possible that the JVM would deadlock on shutdown. This second problem was recovered from when the Wrapper killed the JVM. * Rework the console output from all Wrapper classes to make it much more obvious that that is their source. * Submit a patch to the UNIX sh script by Chris Dance which makes it possible to tell the shell to wait a few seconds for the wrapper to start up. Also includes some modifications to work correctly on older Debian and RedHat systems. * Fix a problem where the local copy of ant was not always being used correctly on UNIX systems which have a default copy of any installed. Thanks to Robey Pointer for the patch. * Add the -lm to the command line when building Linux 32 and 64 bit versions of the wrapper on Linux. This is to support building on recent Debian and Ubuntu versions. Thanks to Robey Pointer for the patch. * Add support for the SIGUSR1 and SIGUSR2 signals so they can now trigger a shutdown, restart or be forwarded to the JVM for custom functionality. See the wrapper.signal.mode.usr1 and wrapper.signal.mode.usr2 properties. Based on a patch by Robey Pointer. Note that the JVM process does not trap SIGUSR1 or SIGUSR2 signals as they are used internally by the JVM as part of the garbage collection process. * Fix a problem where the WRAPPER_OS, WRAPPER_ARCH, and WRAPPER_BITS environment variables were not being initialized correctly for the various unix platforms. * Removed the 4096Mb upper limit set on the wrapper.java.initmemory and wrapper.java.maxmemory properties. 64bit users need to go way beyond that. * Fix a problem where relative include file references in the configuration file were not working correctly if the wrapper.working.dir was used to change the working directory. The working directory is now always reset to its original value as the configuration file is being loaded. * Added a new wrapper.registry.java_home property which makes it possible to specify the location of java within the registry. * Set a new WRAPPER_JAVA_HOME environment variable if the JAVA_HOME is located in the Windows registry. * Modify the way properties are looked up so that any unreplaced environment variable references will be reevaluated in case they were set after the property was originally set. This is possible with some WRAPPER_* environment variables or depending on the placement of set.* properties in the configuration file. * Set any unset properties to their default values internally. This is necessary so the WrapperManager.getProperties() method returns the correct set of active properties. * Fix an occasional crash with 64-bit UNIX caused by a native synchronization problem when system signals are trapped. Bug #1614010. * Fix a problem on Solaris versions, where the Wrapper was not correctly recovering and attempting another back end port when the first was already in use. Bug #1594073. * Fix a problem on Solaris and AIX where the RUN_AS_USER feature of the shell script was not working due to lack of support for the "-m" option of su. The shell script now uses "su -". Bug #1590168. * Add HP-UX Makefiles for building with make. Fix some problems in the shell script to make the script work better on HP-UX. Thanks to David Brown and Nicolas Varney for the patches. * Fix a problem where any signals received by the JVM and triggering a SIGCHLD signal in the Wrapper were being interpretted as the JVM having stopped. This was not always true. Bug #1643666. * The Wrapper is now able to detect when the JVM process is stopped and continued. It will still timeout if stopped, but a descriptive warning is now logged. * Increase the maximum number of log entries which can be queued to avoid losing them. These are only used for log entries outside of the primary thread. * Fix a problem in the shell script which was making it impossible to stop the Wrapper or query its status on OSX. * Add support for 64 bit AIX. Thanks to Nicolas Varney for supplying a Makefile. * Correct the AIX library extension to be ".a". * Rename the UNIX Makefiles so it is more obvious which tool must be used to build with them. * Fix a problem where the HP-UX native library would not be located correctly for some processor types if the file had a platform specific name. * Internally rename the WRAPPER_JSTATE_LAUNCH state to WRAPPER_JSTATE_LAUNCH_DELAY for clarity. * Fix a problem where the UNIX versions of the Wrapper would shutdown rather than restarting a frozen JVM if the arrival of the SIGCHLD signal from the old JVM process was delayed by more than a second or two. * Rework the Windows build so it now uses nmake and a Makefile rather than vcbuild. This is probably not as clean, but it was needed to get the 64-bit build working. * Fix a problem on Windows versions where quoted values specified from the command line were not always being requoted correctly when generating the java command line. * Add validation checks for Windows versions to make sure that all additional parameters, application arguments, the classpath, and library path all contain values which are quoted correctly. Incorrectly quoted values will now result in a warning message that will help resolve the problem. * Fix a memory leak when calling WrapperManager.listServices() on Windows. Bug #1665947. * Fix a buffer overflow problem if the Wrapper was launched without explicitly specifying a configuration file. * Add tests of the return values of all malloc calls to catch out of memory errors and recover as gracefully as possible. Bug #1649880. * Modify the WrapperManager.signalStarting and signalStopping methods so that they will never have the effect of shortening the existing timeout. Updated the javadocs of both methods so they more accurately reflect what the methods do. * Move the Wrapper Copyright banner into the Wrapper process so it will be output more consistently. * Branch the code to support Community, Standard, and Professional Editions of the Java Service Wrapper. * (Standard, Professional) Add support for Server (Fixed) as well as Development (OEM based) licenses. * (Standard, Professional) Add 64-bit versions of the Windows version. The 64-bit Community Edition will not be distributed initially to support ongoing development costs. * (Professional) Add event handling callbacks for Wrapper start/stop, JVM start/stop, JVM started/stopped, JVM restart, JVM killed, and JVM unexpected exit events. * (Professional) Add the ability to send emails in response to any event callback. * (Professional) Add the ability to execute a a user configured command in response to any event callback. * Add WRAPPER_BIN_DIR and WRAPPER_WORKING_DIR environment variables which are now available for use within the wrapper.conf file as well as by any child processes. * Add documentation to the integration pages about existing system properties that be used to control the way the WrapperSimpleApp and WrapperStartStopApp handle application startup. * Remove support for native PPC and x86 distributions of the Wrapper for MAC OSX in favor of the universal X-Code distribution. This appears to be the standard for the market and saves lots of time on testing. * Add a new '-it' command to the Windows version which makes it possible to install and start a service as a single command. * Fix a problem where the PATH environment variable was not being set correctly on Windows versions when run as a service if the wrapper.ntservice.account was set and a PATH was set for both the SYSTEM and user accounts. Bug #1702274. * Modify the shell script to set JAVA_HOME to the default JVM location on OSX systems if it is not already set. OSX always places the JVM in a known location so this is possible. Thanks to Andrew Williams for the patch. * Fix a problem where the UNIX shell script would fail if the APP_NAME was set to a value containing spaces. Thanks to Andrew Williams for the patch. Bug #1695678. * Fix a problem where the DIST_ARCH was not being resolved correctly on HP-UX systems. Thanks to Matej Kraus for the patch. Patch #1697421. * Log output from the timer thread was not being queued correctly, this could have lead to timing problems if there were any delays writing to disk. * Add partial support for OS/400 into the build file. Still needs a Makefile. * Fix a problem where the WrapperActionServer would deadlock in its stop method if the JVM shutdown was initiated by a call to the shutdown or restart actions. * Add support for wrapper.console.title on UNIX platforms. Add a set of wrapper.console.title. properties which make it possible to set the title based on the platform. * Fix a problem where the wrapper.ntservice.account and wrapper.ntservice.password properties were being stored in the system registry if the they were specified on the command line when the Wrapper was installed as a service. This was broken in version 3.2.2. Bug #1538725. * Fix a problem where the DUMP command was not working with the wrapper.commandfile property when run as a service on Windows. Bug #1644421. * Fix a problem where wildcards like "*.*" or "*" in a classpath property were including the "." and ".." files on Windows versions. Bug #1517928. * Modify the debug log output when the Wrapper is attempting to load its native library in an attempt to make the expected failures less threatening. * Commit a patch by Rob Oxspring which adds the start_msg and stop_msg commands to the shell script. These are expected by init scripts on HP-UX. Patch #1750027. * Add a DETAIL_STATUS flag to the UNIX shell script which will cause the status, start_msg, and stop_msg commands to display the current internal status of both the Wrapper and Java processes. * Commit a patch by Rob Oxspring which adds an init block to the UNIX shell script to make it work with install_initd and remove_initd scripts used by SUSE linux. Patch #1750028. * Commit a patch by Travis Carlson, ia64 systems were being grouped as "x86" systems. They now are assigned the name "ia" which makes it possible to create a distribution for them. Patch #1663887. * (Standard, Professional) Add new wrapper.java.initmemory.percent and wrapper.java.maxmemory.percent properties which make it possible to set the initial and maximum memory values relative to the amount of physical memory on the system. Feature Request #1741051. * Add a new #include.debug declaration in the wrapper configuration file which makes it much easier to debug problems with cascading include files. * Add -l and --controlcode commands to the Windows version which make it easy to send user defined control codes to the Wrapper running as a service. * Fix a synchronization problem in the logging code which could result in data corruption or access violations. * Add version numbers to the bat and sh scripts to make them easier to support. * Make the wrapper.ntservice.name, wrapper.ntservice.displayname, and wrapper.ntservice.description properties aliases of new wrapper.name, wrapper.displayname, and wrapper.description properties as they are now used on UNIX platforms as well as Windows. * Fix a problem where the wrapper would sometimes fail to send a packet to the JVM because the sending of the packet would block. Thanks to Peter Gorgon for the patch. * Fix a problem where CPUs identifying themselves as 'ia64n' or 'ia64w' were not correctly being categorized as 'ia'. Thanks to Stirling Chow for the patch. Patch #1859412. * Add -d and --dump commands to the Windows version which make it possible to send thread dump requests to the Wrapper when running as a service. Works in association with the new wrapper.thread_dump_control_code property. Feature Request #1118110. * (Professional) Add wrapper.timer..interval and wrapper.timer..action properties which make it possible to schedule Wrapper shutdowns, JVM restarts and thread dumps at arbitrary times. * Fix a problem where the default configuration file name was being corrupted by a buffer overrun. Thanks to Rob Joyce for the patch. Patch #1879049. * Fix a problem where the WrapperManager would sometimes attempt to unregister its shutdown hook after the shutdown hook had been initiated. Bug #1799489. * Fix a problem where log files were limited to 2GB on Linux systems. Bug #1881038. 3.2.3 * Add support for x86 Mac OS X distributions. * The 3.2.2 Windows version was accidentally released with its MFC libraries dynamically linked. This meant that anyone who did not have VS8 installed were not able to run the Wrapper due to missing DLLs. This version fixes that snafu by correctly using statically linked libraries as was done in previous versions built with VS6. Bug #1578554. 3.2.2 * Correct a typo in the usage output of the WrapperStartStopApp. Thanks to Michael Giroux for pointing it out. * Fix a problem on OSF1 systems where the backend socket was not listening correctly due to a backlog of 0. This was broken in 3.2.0. Thanks to Phillip Gussow for supplying a patch. * Remove the com.silveregg.wrapper package classes that were deprecated in version 3.0.0. * Fix a potential problem in the UNIX script where the lock file permissions were not being set correctly if the LOCKFILE and RUN_AS_USER variables are specified but the group of the specified user could not be resolved. * Fix a problem where the exit code returned by WrapperListener.stop was being ignored in some cases. * Fix a problem where the shell script would not work correctly when the wrapper or its configuration files were located in a directory path containing spaces. * Apply a series of patches by Michael Saya to get the Windows 64 bit build working. * Fix a problem in UNIX versions where the SIGTERM handler was being disabled when a SIGCHLD was received. * Added support in UNIX versions for the SIGHUP signal. * Migrated the source to Subversion from CVS. Did a bunch of cleanup in the source, removing CVS specific tags. * Fix a problem in UNIX versions were the pid file specified by the wrapper.java.pidfile property contained the wrapper pid rather than the jvm pid. Bug #1565011. * Fix a problem in UNIX versions where the file specified by the wrapper.java.pidfile property was not always being deleted when the JVM process went away. * A user encountered a JVM bug where calls to System.exit were resulting in an IllegalThreadStateException being thrown. Added some code to trap this and shut down the JVM using other means to avoid a hang during shutdown. * Fix a NullPointerException caused by users incorrectly implementing an Integration Method #3 class and then calling WrapperManager.start with a null value for the args parameter. * Update the banner displayed by the Wrapper on startup to include a copyright notice. Please see the license page of the documentation for details. * Add a new 'Z' log format which will log the time to millisecond accuracy. * Fix a problem where the JVM exit code was not being set correctly when the JVM was shutdown using WrapperManager.stopImmediate(). The exit code of the Wrapper was being set correctly through other means however. * Fix a potential synchronization problem in the logging code if a JVM exits with debug output enabled. * Updated the WrapperListener.stop method javadocs to better explain the exitCode value under certain exit modes. * On UNIX versions, add a log message which records the signal that caused the JVM process to exit when it terminates unexpectedly. * Fix a problem where the wrapper.on_exit. property was not working correctly in some cases on UNIX. With help from Andreas Schafer. * Add support for building the Wrapper with Visual Studio 8 for Windows. Releases will now be done using this compiler. * Fix a CRITICAL bug in the 3.2.0 and 3.2.1 Windows versions of the Wrapper where the Wrapper would crash under rare circumstances when running as a service. If the service manager interrogated the service at the same instant as the wrapper was pinging the JVM, the wrapper was sometimes crashing due to a synchronization problem. The problem did not exist prior to 3.2.0. Bug #1574537. * Fix a minor logging problem where the 'D' format was not displaying the correct thread name for queued log messages. 3.2.1 * Fix a problem with the solaris-sparc-64 makefile. * Add a solaris-x86-64 makefile. * Merge in a patch by Hugo Weber to make it possible to configure the Wrapper to pull the JRE from the system registry on windows. * Fix a batch file bug added in 3.2.0 where the scripts would not function correctly if the full path to the batch file contained spaces. Bug #1450601. * Modify the message shown when a native library fails to load so the exception message text is now shown in the log without having to enable debug log output. * Modify the UNIX shell script to be more informative if the script is unable to locate a wrapper binary due to a executable bit permission problem. * Fix a minor permission problem with the build for the delta-pack. * Commit a patch by Juergen Hermann to make the error shown when realpath fails clearer. * Add the ability to use a default wrapper.conf file that is in the same directory as the wrapper binary. The file will be named based on the name of the wrapper binary. * Synchronize the command line so that both the Windows and UNIX versions are now the same. The old command line syntaxes are now supported everywhere so there will be no compatibility problems. * It is no longer possible to specify arguments using the '/c' syntax. This was undocumented so hopefully it is not being used. The documented '-c' syntax must now be used. The change was necessary to synchronize the command line between UNIX and windows platforms. * The 32-bit HP-UX 3.2.0 build was generating a libwrapper.so file rather than libwrapper.sl. * Make the WrapperManager.setConsoleTitle, getWrapperPID, and getJavaPID methods available through JMX. * Fix a state engine problem introduced in 3.2.0 which was causing the wrapper.on_exit. properties to be ignored in most cases. * Fix a potential problem that could have caused crashes when debug logging was enabled. * Fix a problem where signals were not being handled correctly on some UNIX platforms, including AIX. This was making it impossible to shutdown the wrapper cleanly with the TERM signal. Bug #1477619. * Add new default environment variables which can be referenced in a configuration file to configure platform specific directories and file names. WRAPPER_OS, WRAPPER_ARCH, and WRAPPER_BITS. * Add a -v argument to make it possible to request the version from a wrapper binary. * Add support for registering the WrapperManager MBean with the PlatformMBeanServer when run on a 1.5+ JVM. See the JMX section in the documentation for details. * Rework the way timeout properties are handled. Values of 0 now actually disable the timeouts rather than setting them to a large value. To avoid overflow problems when converting to internal timer ticks, timeouts are now restricted to a maximum of 20 days, or 1728000 seconds. Change affects the wrapper.cpu.timeout, wrapper.startup.timeout, wrapper.ping.timeout, wrapper.shutdown.timeout, and wrapper.jvm_exit.timeout properties. For values less than 20 days, there should be no change in functionality. * Add support for debuggers. The Wrapper will now show a warning on startup and then again the first time a timeout occurs. But all timeouts will be ignored. This is to avoid problems with the Wrapper restarting a suspended JVM in the middle of a debugging session. The wrapper enters this mode if the wrapper.java.command ends with the string "jdb" or "jdb.exe", or the "-Xdebug" parameter is passed to the JVM. * Add 'athlon' to the list of supported architectures. * Fix a problem where the environment variables loaded when a service was started were always the system environment even if the service was running as a specific account. The environment of a specific account will now be loaded on top of the system environment if the USERNAME environment variable is set by the system. Bug #1491138. * Added new wrapper.ntservice.pausable and wrapper.ntservice.pausable.stop_jvm properties to make it possible to pause and resume the Wrapper when installed as a Windows service. * Added new Pause and Resume batch files as well as modified the command batch file to support pause and resume. * Added PAUSE and RESUME commands for use by the wrapper.commandfile property. * Fix a problem with the wrapper.pidfile, wrapper.java.pidfile, wrapper.anchorfile, wrapper.commandfile, wrapper.statusfile, wrapper.java.statusfile, wrapper.java.idfile, and wrapper.lockfile properties where forward slashes in paths were not being changed to back slashes on Windows versions. * Simplify the code used to load a native library by using the System.mapLibraryName method rather than doing the same thing manually. * Add a new wrapper.syslog.facility property which makes it possible to specify the syslog facility on UNIX systems. Thanks for the patch from Bruce Pennypacker. * Removed the custom thread counting used to keep track of when the wrapped Java application has completed. It is now done in a different way that will work on all Java implementations without requiring any special consideration of the current JVM. Deprecated the wrapper.monitor_thread_count and wrapper.thread_count_delay properties. Bug #1470265. * The WrapperStartStopApp helper class still requires thread counting if the stopWait parameter is set to true. Previous versions all hardcoded the system thread count to 1 which worked for most JVMs. A new system property, org.tanukisoftware.wrapper.WrapperStartStopApp.systemThreadCount, was added to make it possible to customize. It currently defaults to 1. * Make it possible to extend the WrapperSimpleApp and WrapperStartStopApp helper classes. Feature Request #1510274. * Add warning messages if the old org.silveregg.wrapper package classes are still being used. They will be removed in the next release. 3.2.0 * Rework the release cycle so that the wrapper.jar file released for all platforms is now built on the same machine. This resolves a few incompatibility problems caused by jars built on very new JVMs but run on old JVMs. * Add additional output when the JVM can not be launched due to security restrictions on Windows. * Greatly improved the performance of file logging. On a windows test machine 3.1.2 could log 67210 lines of output in 20 seconds with a 80-15% split between the Wrapper and JVM process CPU usage. It now outputs 215214 lines with a 64-34% split, also showing less load on the system process. This is a 220% increase in performance. In both cases, the JVM was completely idle other than the console output which makes the Wrapper appear to be a bit of a CPU hog. In fact it is the only process doing any work in this case. This improvement was accomplished by keeping the log file open unless idle. The idle time can be controlled using the new wrapper.logfile.inactivity.timeout property. The speed increase on UNIX platforms was much smaller at around 10%. * Add a new property, wrapper.disable_restarts, which will completely disable the Wrapper's ability to restart JVMs. * Add a pair of new properties, wrapper.port.min and wrapper.port.max, which make it possible to define the port range used when a specific wrapper.port is not specified. * Fix a problem where certain characters like umlauts were being stripped from property values. Bug #1049528. * Make the PIDs of the Wrapper and Java process easier to access by providing a new pair os system properties; wrapper.pid and wrapper.java.pid, as well as a new pair of methods; WrapperManager.getWrapperPID() and WrapperManager.getJavaPID(). * Add a new WrapperEventListener class which can be implemented to receive a wide variety of events from the Wrapper. * Add a WrapperServiceControlEvent class which will report any service control codes received by the Wrapper as it is running as an NT service. This was added to make it possible for other applications to sent custom codes to the Wrapper using the Window Service Manager. * Add a WrapperManager.listServices() method which can be used to obtain the status of all services on a Windows system. * Add a WrapperManager.sendServiceControlCode() method which makes it possible to start, stop, pause, continue, any service on Windows systems. It is also possible to send custom user codes via the service manager. * Add comments in the sh script to support the chkconfig command. * Implement the ability to read from standard input via System.in. Feature Request #1024693. * Made the tick based timer the default by changing the default value of the wrapper.use_system_time property to false. Most users should see an improvement in reliability under heavy loads with this new setting. If you have extended any timeouts in the past, you may wish to try going back to defaults as they may no longer need to be extended. * Add a new wrapper.restart.reload_configuration property which causes the Wrapper to reload its configuration file immediately before a JVM restart. Properties which can not be reloaded have comments stating that fact in their documentation. Feature Request #981060. * Fix a problem in the UNIX shell script which was preventing the script from locating the PID and anchor files when the wrapper.working.dir property was used. * Modify UNIX versions so that the wrapper binary will now force its working directory to the location of the wrapper binary. This change was made to make the UNIX version work the same way as the Windows version and thus make configuration files that modify their working directory work correctly on a cross platform basis. Users which have been using the scripts supplied with the Wrapper should not encounter any problems. Other users may require slight changes to their configuration file to deal with the new way that the Wrapper deals with its initial working directory. * Add a new method WrapperManager.getProperties() which makes it possible to access any property in the Wrapper configuration file. * Fix a problem where TERM signals were not being correctly ignored by the JVM process on UNIX platforms even if the wrapper.ignore_signals property was set to true. Earlier versions of the Wrapper would generate a WRAPPER_CTRL_SHUTDOWN_EVENT when a TERM signal was received. On Windows that signal should never be ignored. To resolve this a new WRAPPER_CTRL_TERM_EVENT was added making it possible to selectively ignore the TERM signals. This change may affect user implementations of the WrapperListener.controlEvent() method. Bug #1086344. * The Windows version has a feature which allows the user to immediately kill the Wrapper and its Java application without waiting for a clean shutdown by pressing CTRL-C twice. Windows sends the CTRL-C signal to both the Wrapper and Java processes. Due to a rare timing problem, it was possible for the Java process to get the signal first and initialize a shutdown before the Wrapper could respond to the signal. In this case the Wrapper was interpreting this as a second CTRL-C signal even though the user only pressed it once. * If the wrapper.anchorfile or wrapper.pidfile properties are used on Windows they were being unintentionally deleted if the -t, -p, -i, or -r commands were used while another Wrapper instance was running. In the case of the anchor file, this would result in the Wrapper being shutdown unintentionally. This was not an issue on non-Windows versions. Bug #1108517. * Fix a security problem where the value of the wrapper.ntservice.account and wrapper.ntservice.password properties were being stored in plain text within the registry if they were specified on the command line when installing the Wrapper as a Windows service. Bug #1110183. * Add a pair of properties wrapper.ntservice.password.prompt and wrapper.ntservice.password.prompt.mask which which will cause the Wrapper to prompt the user for an account password when it is being installed as an NT service. * Added system properties to make it possible to configure whether or not the WrapperSimpleApp and WrapperStartStopApp helper classes will wait for the configured main methods to complete before reporting that the application has started. See the javadocs for these classes for more details. * Modify the HP-UX build so that it now dynamically links with the pthread library. This was to make the binaries work with HP-UX 11.00. Thanks to Sun Kun Choi for the patch. * Add new wrapper.statusfile and wrapper.java.statusfile properties which can be used by external applications to monitor the internal state of the Wrapper or JVM at any given time. These will not be useful to most users. * Add a new wrapper.commandfile property which can be used by external applications to control the Wrapper and its JVM. * Add a new wrapper.java.idfile property which can be used by external applications to monitor the internal state of the JVM at any given time. * Add a warning on startup if the JVM has a SecurityManager set but the wrapper.jar has not been granted the AllPermissions permission. Failure to do so will almost certainly lead to the Wrapper throwing a number of errors and this helps to point out the cause. * Add a security model which protects most Wrapper method calls when a SecurityManager has been registered. See the Security Model section for more details. * Add a new pair of batch files which can be used to start and stop the Wrapper when installed as a service. * Add new -q and -qs commands to the Windows version of the Wrapper which make it possible to query the currently installed status of the service. * Fix a problem where the wrapper.java.library.path.append_system_path property was not working correctly on Windows when the system PATH contained quotes. Bug #1238726. * Modify the usage output of the Wrapper on all platforms so the Wrapper's version is now included. It was not previously possible to get the version of the Wrapper being used without launching a JVM. * Add a pair of new methods WrapperManager.stopAndReturn() and WrapperManager.restartAndReturn() which make it possible for code to stop or restart the JVM and then continue until the JVM is shutdown. This can be useful for shutdowns initiated within places like servlets, whose operation is expected to complete. * Fix a problem on UNIX where the child JVM was sometimes leaving around zombie processes after a restart. The SIGCHLD signal was not being handled correctly. Thanks to Traun Leyden for the patch. Bug #1291201. * Implement the ability to catch control events using the WrapperEventLisener. Feature Request #836975. * Add new wrapper.jvm.port, wrapper.jvm.port.min, and wrapper.jvm.port.max properties which make it possible to control the port the JVM uses to open a connection back to the JVM. The Wrapper uses to leave this up to the OS, but some users were having problems with the default conflicting with other ports. * Switch from using ftime() to gettimeofday() on UNIX platforms to work around a problem where the Wrapper would not run on new versions of OSX because they deprecated the ftime() function call. Thanks for the patch by Michael Macaluso. Bug #1313162. * Remove the shutdown timeout from the UNIX shell script. It is not needed and can cause a zombie JVM if the wrapper's internal shutdown timeout was longer than that of the shell script. * Add the ability to specify integer property values in base 8 or 16 in addition to base 10. Base 8 values start with a '0' and base 16 values start with a '0x'. * Make it possible to set the umask on all files created by the Wrapper as well as the default umask of files created by the JVM. Added new wrapper.umask, wrapper.java.umask, wrapper.pidfile.umask, wrapper.lockfile.umask, wrapper.java.pidfile.umask, wrapper.java.idfile.umask, wrapper.statusfile.umask, wrapper.java.statusfile.umask, wrapper.anchorfile.umask, and wrapper.logfile.umask properties. * Improve the message when the native library can not be loaded to make mention of the possibility of a 32/64 bit mismatch. * Add a new wrapper.monitor_thread_count property which makes it possible to disable the Wrapper's counting of non-daemon threads and thus the shutting down of the JVM when they have all completed. * Add support for BELOW_NORMAL and ABOVE_NORMAL options to the wrapper.ntservice.process_priority property. Feature Request #1373922. * Ignore '#' characters which are included within double quotes in the value of a property in the configuration file. Unquoted values must be escaped with a second '#' characters or it will be interpreted as a comment. * Display the Wrapper banner in the JVM earlier so that it is displayed even where there are startup errors. * Modify the WrapperSimpleApp and WrapperStartStopApp classes so that the WrapperManager is always initialized immediately. This makes the output clearer in the event of startup errors. * Fix a problem where the Windows ServiceManager was not correctly reporting a startup error if a service failed on startup. The service was being reported as having started even though it failed to start. * Fix a problem on UNIX versions where the Wrapper would go into a recursive state of attempting to launch the JVM from failed child processes if there was any problems executing the configured java process. * Rework the way the RUN_AS_USER setting in the UNIX shell script works so the specified user is now set regardless of the command being executed. To make sure the user never has to enter the password twice when running the script, it now recurses after changing the user. The script then runs entirely as the configured user. * Improve the message that is displayed when attempting to start, stop, or remove a windows service which is not installed. * Add new wrapper.lockfile property which makes it possible to specify a lock file containing a pid. * Modified the sh script so it now creates a lock file on startup in the /var/lock/subsys directory if it exists. This is needed by fedora systems on shutdown. * Store javadocs in tar distibutions in a nested tar file to avoid problems with long filenames in some tar distributions. * Fix a problem with the WrapperSimpleApp and WrapperStartStopApp helper classes where on heavily loaded systems it was possible for the Wrapper to get a running thread count of 0 and shutdown before the main thread had a chance to be started. * Add a new wrapper.thread_count_delay property which will force the WrapperManager to wait the specified number of seconds before it begins to check the number of running threads. * Fix a problem where the wrapper.java.library.path.append_system_path property was appending the PATH rather than the LD_LIBRARY_PATH environment variable on Unix systems. PATH is correct for Windows systems. * Add a new wrapper.logfile.rollmode property which makes it possible to control how and when the logfile is rolled. Feature Requests #864463, #1085097, and #1085850. * Fix a problem on Linux where the test for the status of the Java child process would sometimes fail causing the Wrapper to shutdown with the error "Critical error: wait for JVM process failed (No child processes)" rather than restart the child JVM. Users who encountered this problem found it easy to reproduce, but it only happened on some systems. * Modify the way the UNIX shell script tests for the existence of a process matching the pid in an existing pid file. It now verifies the process command as well as the pid to fix a system reboot problem where a stale pid has been reused by another application, making the script think the wrapper was already running. * Add support for the GNU libjcj JVM. Like JRocket, it requires slightly different thread counting. * Add support for Linux 64-bit PPC and Solaris 32-bit x86 versions. * Add a new set.default.ENV syntax to the configuration file making it possible to environment variable values which do not overwrite existing values, ie. to specify a default value. * Added a new wrapper.console.flush property which forces the wrapper to explicitly flush stdout after each line of log output. * Change the error shown when the JVM shuts down prematurely during a shutdown to a warning message. * Fix a problem where the Wrapper would show the following error message if user code called System.exit from within the WrapperListener.stop callback method. This would happen if the stop class's main method registered with the WrapperStartStopApp called System.exit. "JVM exited unexpectedly while stopping the application." Bug #945976. * Add a new wrapper.syslog.ident property which makes it possible to specify the identity used in syslog entries on UNIX. This was possible in older versions but was set using the wrapper.ntservice.name property. Bug #1432855. * Add support for MacOSX Universal Binary distributions. * Add support for Delta Pack distributions. This is a distribution that contains the binaries of multiple platforms. 3.1.2 * Modify the way boolean system properties are resolved by the WrapperManager so it is now possible to set them to true or false rather than assuming they are true if set. * Fix a problem where some localized error messages were not having their tokens replaced correctly. * Fix a problem when using the WrapperStartStopApp helper class. The usage text was incorrectly being displayed in the console if an exception was thrown while executing the main method of the configured stop class. This did not change the functionality of the application, but it did cause some confusion. * Fix a problem on Windows where a library path or class path which ended in a backslash was preventing the Wrapper from launching the JVM. The Windows OS was using the backslash to escape the quote used to close the path. The fix was to add a second backslash where needed. * Added a new wrapper.java.command.loglevel property which makes it possible to control the log level of the generated java command. * Add support for escaped quotes when stripping quotes on UNIX for the wrapper.java.additional. and wrapper.app.parameter. properties. * Change the default value of wrapper.jvm_exit.timeout from 5 to 15 seconds. The old default was too fast for some applications which take a while to exit. Applications which were exiting promptly will not see any difference. * Fix a problem where the JVM would restart at certain times when using the system time based timer due to an overflow error. This problem was introduced in 3.1.0. Due to a separate bug in 3.1.0, the Wrapper would shutdown rather than simply restarting the JVM as was happening in 3.1.1. The last restart happened on Aug 21, 2004. It will next occur Oct 10, 2004 and repeat at regular intervals. There are no problems when using the new Tick based timer. Bug #1014405. * Correct the wrapper.logfile.maxsize property so that a a kilobyte is now 1024 rather than 1000, and a megabyte is a megabyte. We aren't a hard drive manufacturer after all. * Add try-catch blocks around all thread entry points in the Windows version. This has always been done in the main function, but these blocks will help to narrow down the cause of problems should they ever be encountered in control or service handlers. * Centralize shutdown code on UNIX version in an appExit method as was already being done for Windows versions. * Fix a problem where the build.sh was not correctly using the included ant if an ANT_HOME environment variable was defined. * Add a new wrapper.single_invocation property which will prevent multiple invocations of an application from being started on Windows platforms. The shell script handles this on UNIX platforms. Feature Request #889123. * Fix a crash problem introduced in 3.1.1, caused by a pair of uninitialized pointers. The crash was possible on all platforms but would only happen if the Wrapper was started without any arguments. It would not affect users running the Wrapper normally. Bug #1018481. * Fix a problem with the run as user feature of the shell script on Solaris. Needed to be using /usr/xpg4/bin/id rather than /usr/bin/in if available. Bug #1024008. * Replace calls to usleep with nanosleep on platforms where it is available. This was to fix an occasional hang on a specific Solaris machine. It would occasionally hang on calls to usleep. From research, it appears that usleep has problems when signals are encountered while sleeping. Still testing whether or not this change solved the problem. * Upgrade the version of Ant included with source releases to 1.6.2 to fix some problems generating jni headers when building with Java 1.4.2. * Upgrade the version of Cocoon included with source releases to 2.0.4 to fix some problems generating documentation using Java 1.4.2. * Display a warning if the exit status of a JVM process ever returns the STILL_ACTIVE status on Windows. There was no known problem here, just noticed it while looking over the code. * Display a descriptive error message on Windows if the the JVM process crashes due to an uncaught exception in native JVM code. * Add a test for invalid jvm arguments set using the wrapper.java.additional. properties. Invalid arguments could cause the Wrapper startup to fail in non obvious ways if they are mistaken by the JVM as the main class. 3.1.1 * Modified the way libwrapper.so is built on Solaris and Linux so that it no longer statically links its required libraries. * Fix a file handle leak when calling WrapperManager.getUser or WrapperManager.getInteractiveUser on Windows platforms. * Fix a problem introduced in 3.1.0 where the JVM would not be restarted correctly if it quit after a ping timeout to let the Wrapper resynch and restart it. * Fix a problem where CTRL-C was not being handled correctly if the console was configured to be shown when running as an NT service. * Fix a problem where signals fired at UNIX versions of the wrapper were not being handled correctly when the tick timer was being used. * Fix a synchronization problem in the logging code which would occassionally cause the Wrapper to crash with an Access Violation. The problem was only encountered when the tick timer was enabled, and was only seen on multi-CPU systems. Bug #949877. * Fix a problem when using the tick timer where the Wrapper would sometimes exit on startup due to an uncaught SIGALRM. Only reported on multi-CPU Solaris systems. * Fix a problem where the Wrapper would sometimes hang on shutdown if another thread called System.exit while the Wrapper was shutting down. Bug #955248. * Fix a problem introduced in 3.1.0 where a very very large CPU timeout warning message was being displayed if the system time was set back while using the default system timer. * Added a new property, wrapper.anchorfile, which makes it possible to cause the Wrapper to shutdown by deleting an anchor file. The UNIX sh script has been modified to optionally make use of this feature. * Add a debug message at startup which makes it clear which timer is being used. * A Windows user reported that using forward slashes in the path the log file was failing. Avoid this problem by always converting '/' to '\' in the wrapper.logfile property on Windows. * Fix a problem where it was not possible disable the wrapper log file as documented in the wrapper.logfile property. Most likely broken way back in version 2.2.5. * Add some additional error checks after calls to control the pipe between the JVM and Wrapper as well as improving the messages around other socket related error messages. * Fix a problem on some HP-UX systems were not working correctly because the EAGAIN and EWOULDBLOCK constants are not equal with some compilers. * Change some of the defaults in the src/conf/wrapper.conf.in file which ships with the Wrapper to avoid confusion with new users. * Rewrote the routine which reads and logs console output from the JVM for Windows versions. Internal buffers are now scaled dynamically, fixing a problem where long lines were being wrapped at 1024 characters. This rewrite also resulted in a 4 fold increase in speed when the JVM is sending large quantities of output to the console. * Increase debug output on UNIX platforms when a signal is caught. When possible, information about where the signal came from is now logged. * Modified the way log output from within signal handlers is handled so it is now queued and then logged by the main event loop. * Back out a 3.1.0 change where a JVM that had failed to exit cleanly was sent a SIGTERM prior to a SIGKILL. The SIGTERM made no difference and slowed down the forced shutdown. A modification to the event loop made the functionality more difficult to implement. * Add the ability to set the user that the Wrapper and its JVM will run as from within the sh script on UNIX platforms. * Add an icon resource to the Wrapper binary on Windows versions. * Fix a typo in the UNIX sh script which caused an extra slash to be included in the path of the pid file. Was not causing any known problems. * Added support for 64-bit HP-UX. Big thanks to Venkatesh Sellappa for supplying the patch. * Fix a deadlock problem introduced in 3.1.0 with some FreeBSD systems. Not all users were experiencing it, but those who did were able to reliably reproduce the problem. The problem appears to have been caused by FreeBSD bug #kern/64313. * Make the signal handling variables in the wrapper native library volatile. Directly this was to fix a compiler warning on HP-UX64 systems but it should also make the calls more efficient. 3.1.0 * The license was revised for this version to include a copyright omission. This change is to be retroactively applied to all versions of the Java Service Wrapper starting with version 3.0.0. The changes should have no effect on users. * The Online documentation and web site were both reworked. The logo has been updated so that Duke is no longer used. The new online site now has the ability for users to logon and append comments to any page. * Added a new batch file which accepts commands like the UNIX shell script. The new file is offered as an alternative to the default batch files, and can be found at src/bin/AppCommand.bat.in. Thanks to Mike Castle for donating the new script. * The Windows version of the Wrapper was not correctly registering that it would accept SHUTDOWN messages when running as a service. The Wrapper was getting the message anyway so this should not change functionality. Thanks to Jason Tishler for noticing this and sending in a patch. * Add a new property, wrapper.native_library, which can be used to specify the base name of the native library which is loaded by the WrapperManager class. * Modify the WrapperManager class so it now stores references to System.out and System.err on initialization and always writes to those stored streams. This makes sure that all Wrapper console output always goes to the wrapper.log file even if user code overrides those streams with calls to System.setOut and System.setErr. This was necessary to prevent deadlocks in such user code from affecting the functionality of the Wrapper. * Fixed a problem where some environment variables where not being correctly loaded from the system registry when running as an NT service. Big thanks to Eric Smith for tracking this down and submitting a patch. It turns out that the putenv function was not being used correctly. * Modified the way the wrapper.conf file is loaded so it will now read the contents correctly even if the line feeds in the file are incorrect for the current platform. Windows line feeds had been causing problems when used on UNIX platforms. Feature Request #829896. * Added a new property, wrapper.ntservice.console, which allows a console to be displayed when running as an NT service. * Fixed a problem where the request thread dump on failed JVM exit feature had never worked when running as an NT service. Bug #831775. * Add a new property, wrapper.console.title, which makes it possible to set the title of the console in which the Wrapper is currently running. This currently only works on Windows platforms. * Added a new method, setConsoleTitle, to the WrapperManager class which enables the application to dynamically set the console title. Like the wrapper.console.title property, this only works on Windows platforms. * Improved the algorithm of the request thread dump on failed JVM exit feature so that extremely large thread dumps will not be truncated when the JVM is killed. * Fix a problem where CTRL-C was being ignored by the WrapperManager if a WrapperListener is never registered. This is not possible if the Wrapper is being used correctly but never the less a user did come across it. * Add some additional debug output to help identify the cause of problems loading the native library. * The WrapperManager class now checks to make sure that its current version matches the version of the native library and Wrapper. If there are any discrepancies found then appropriate warnings will be displayed, but the Application will still be allowed to start. This was added to make obvious the cause of problems resulting from mismatched versions. * Added a new property wrapper.use_system_time system time. By setting this property to false, the Wrapper will start using a new experimental timer which uses a background thread to manage time rather than the system time. This has a number of advantages over using the system time and should give most users even more reliable behavior when the system is under high load or there are changes being made to the system time. The timer is very critical to the operation of the Wrapper so the old behavior is left as the default for the time being until this feature has had the chance to be "time" tested. If all goes well then this will be enabled as the default in a future version of the Wrapper. A pair of related properties, wrapper.timer_fast_threshold and wrapper.timer_slow_threshold were also added to aid in debugging. * Rework the logging code so it is now thread safe. The addition of the timer thread means that there is now more than a single thread accessing that code. This was causing problems as the two threads tried to use the same buffers. As part of this change, a new format variable 'D' was added to display the thread which is doing the logging. * Fix a problem where a thread dump would be invoked if the request thread dump on failed JVM exit was enabled and the user forced an immediate shutdown by pressing CTRL-C more than once. * Add getUser and getInteractiveUser methods to the WrapperManager class to make it possible for user code to query information about the user running Wrapper or the user who is interacting with the Wrapper and its JVM. Feature Request #812175. * The Wrapper will now always exit with the exit code used to terminate the JVM whether System.exit is used or WrapperManager.stop. When running as an NT service the Wrapper now correctly returns the correct exit code to the service manager so failure recovery tools should now work correctly. Feature Request #852491. * Add a status command to the UNIX shell script which can be used to find out whether or not the wrapper is currently running. Patch submitted by Joseph Benavidez. * Modify the WrapperSimpleApp and WrapperStartStopApp so that the main method of a class is located even if it exists in a parent class rather than the class specified. * To make debugging classpath problems easier, the Wrapper now verifies all classpath entries before launching a JVM and logs debug level warnings for any entries that do not exist. * Fix a problem where it was possible to define a zero length filter that would trigger on any output. * Add some additional debug output to make it easier to debug startup, shutdown and restart problems. * Modify the way the Wrapper forcibly kills a frozen JVM on UNIX platforms so that it now sends a SIGTERM, waits up to 5 seconds, then sends a SIGKILL. * Add a new wrapper.java.library.path.append_system_path property which will cause the Wrapper to append the system path to the generated library path. Feature Request #917902. * Fix a problem where spaces around the '=' character of a property definition were rendering the property invisible to the Wrapper. Bug #916001. * Fix a problem where the first ping timeout after the JVM was started was still hard coded at 30 seconds. This was causing a combination of large values of wrapper.ping.interval and wrapper.ping.timeout to fail. * Fix a problem where the JVM would fail to shutdown cleanly if the Wrapper was asked to stop too soon after launching a JVM. This was leading to the JVM being killed after the shutdown timeout expired. Bug #917281. * Added an adviser which will print out explanatory messages to the console and wrapper log file when the Wrapper encounters a commonly made configuration mistake. This is designed to cut down on support requests by new users. Can be disabled using the wrapper.adviser property. * The bash script and the realpath utility have been deprecated since version 3.0.3. They have been removed in this release. The sh script is recommended on all UNIX platforms, and the realpath utility which was used by pre-3.0.3 bash and sh scripts has not been used since. * Add the wrapper.startup.delay property along with console and service specific variants which make it possible to configure a delay between the Wrapper being launched and the first JVM being launched. * Promote the wrapper.debug property back from being "deprecated". It has continued to be useful and deserved documentation and official status. * Add wrapper.on_exit. properties to control what happens when a exits based on the exit code. * Modify the way calls to System.in.read() are handled so that they now block rather than throwing an exception. Currently, System.in can not be used with the Wrapper because of the way I/O is passed between the Wrapper and JVM. * Modified the Windows batch files to fix a problem where the path to the Wrapper.exe contained more than one "/bin". The new batch files are much simpler and should be easier to customize if needed. Bug #925308. * Modified the wrapper.java.initmemory and wrapper.java.maxmemory properties so that they now default to a value of 0 which causes the -Xms and -Xmx parameters to be omitted from the command used to launch Java. This will cause the JVM to use its own default values and also makes it possible to specify the memory parameters using the wrapper.java.additional. properties. * Added a pair of environment variables, WRAPPER_FILE_SEPARATOR and WRAPPER_PATH_SEPARATOR, whose values are set to either '/' and ':' or '\' and ';' on startup. They can be used in the wrapper.conf file to construct platform independent property values. * Add a new wrapper.working.dir property which makes if possible to change the Wrapper and JVM's working directory to a location other than the location of the Wrapper binary. Feature Request #738160. 3.0.5 * Added support for SGI Irix. Big thanks to Andreas Wendt for supplying the patch. * Due to a bug in the build, the native library was not included in the 3.0.3 or 3.0.4 binary releases for OSX, building from source was working correctly. This has been fixed and the build greatly simplified to avoid such problems in the future. Bug #791755. * Changed the default location of the pid file generated by the sh script to exist in the same directory as the sh script rather than in the /var/run. This can be changed by setting the PIDDIR variable in the sh script used to launch the Wrapper. * Added support for the wrapper.pidfile property on the Windows platform. * Added the wrapper.java.pidfile property which will cause the pid of the java process to be written to a specified file. (WINDOWS USERS) If you are using a wrapper.conf file that was created prior to version 3.0.0 of the Wrapper, then you may have this property defined in your configuration file. You will get an error on startup if the specified path does not exist. * Stop clearing the file creation mask when the Unix version of the Wrapper is run as a daemon process. The file creation mask will not be inherited from the process which launches the Wrapper. Bug #788849. * Modify the sh script so it works on Linux, then deprecate the bash script. This means that all Unix platforms can now use the same script to control the Wrapper. Thanks to Mike Castle for the patch. The bash script can still be found in the release, but it is deprecated and will be removed in a future version. * Modified the sh script so it is now possible to set the nice priority in the script configuration block. * Remove output to System.out in the WrapperManager.requestThreadDump() method. If some JVM threads were hung while accessing the System.out object, attempting to do a thread a dump would cause the calling thread to hang as well. Thanks to Thomas Hart for the patch. * Make it obvious in the log whether or not the Wrapper was started as a daemon process on UNIX systems. * Modify the way restarts requested from the JVM, or caused by a filter are handled. The Wrapper will no longer reset the restart count in either of these cases. If an application runs for longer than the wrapper.successful_invocation_time timeout then the count will still be reset back to 0. * Added a new wrapper.ignore_signals property which makes it possible to configure the Wrapper so it will ignore CTRL-C, HALT and INT signals. * Modify the WrapperManager.isLaunchedAsService() method on UNIX systems so it now returns true if the Wrapper was launched with the wrapper.daemonize flag set. * Added a pair of MBean interfaces which allow the Wrapper to be controlled using JMX. See the new JMX section in the documentation for details. Thanks to Sal Ingrilli for help with testing. * Modify the Windows build so the Wrapper.exe and Wrapper.dll files can now be built from Ant if MSVC is installed. * Added a new wrapper.ping.interval property which lets users control the frequency that the Wrapper pings the JVM. Feature Request #607768. * When a JVM refuses to shutdown, the Wrapper can be configured to request a thread dump using the wrapper.request_thread_dump_on_failed_jvm_exit property. The Wrapper was then waiting 1 second before the process was killed. This was not always long enough, resulting in a truncated thread dump. Increased the pause to 3 seconds. Feature Request #633761. * Fix a bug where wrapper.app.parameter. and wrapper.java.additional. properties declared from the Windows command line were not correctly handling spaces in their values. Support Request #802139. 3.0.4 * Fix a problem on UNIX systems where requesting a second thread dump any time during the life of a single Wrapper process would cause the Wrapper and JVM to shutdown rather than perform the thread dump. * Fix a problem where a, user without permission, attempting to stop an application was able to delete the pid file even though they were unable to stop the application itself. This would make the scripts think that the application was stopped when was actually still running. * Fix a problem where an application was being killed prematurely if it took longer than 6 seconds to exit on its own. The scripts now make sure that an application always has enough time to shutdown cleanly. * Improve the debug output so that packet codes are now shown using a name rather than a raw number. * Reduce the frequency of "Waiting to stop..." messages displayed when removing an NT service that is currently running. Decreased frequency from once per second to once every five seconds. * Fix a minor problem where the hour in the date returned by WrapperInfo.getBuildTime() was not base 24. * Added -t and -p command line options to the Windows version of the Wrapper to sTart and stoP the Wrapper as an NT service. This can be used in place of "net start" and "net stop", which do not always work correctly when a service takes a long time to start up or shutdown. See the Launching Your Application (Win32) section for more details. * Add a new method WrapperManager.stopImmediate which will cause the JVM to exit immediately without calling any stop methods or shutdown hooks. * Add a new class, WrapperActionServer, which makes it easy to remotely control the Wrapper remotely by opening a socket and sending commands. See the javadocs of the class for more details. * Fix bug #744801. A Java GUI was not being displayed when the application was run in either console mode or as a service with wrapper.ntservice.interactive enabled. This problem was introduced in Version 3.0.0 when using 1.2.x or 1.3.x versions of Java. To use interactive services with 1.2.x or 1.3.x versions of java, please review the documentation for the wrapper.ntservice.interactive property. * Fix a problem where the JVM was not receiving CTRL-C and CTRL-CLOSE events when running under the Wrapper on Windows. This was not a problem in most cases as the Wrapper was taking care of the processing of the events. But the WrapperListener.controlEvent() method was not being called as documented. * Changed the way the WrapperSimpleApp and WrapperStartStopApp respond to control events so that the JVM will respond and call WrapperManager.stop() even when being controlled by the Wrapper. * Modified the suggested behavior of the WrapperListener.controlEvent() method. Users who have implemented the WrapperListener interface themselves should review the Javadocs. The changes are not required and applications will continue to function as they did before. * Added support for DEC OSF1 (Alpha). Big thanks to Andreas Wendt for supplying the patch. * Fix a problem where the sh and bash scripts were failing if the path to the script contained spaces. * Fix a problem where the JVM would sometimes hang when trying to shutdown if the wrapper.key parameter was passed to the JVM while not being controlled by the Wrapper. This would happen if a user copied the command from the Wrapper's debug output and attempted to run it as is without first removing the wrapper.key parameter. * Implement the ability to specify an NT service's load order group in response to feature request #764143. See the javadocs for the new wrapper.ntservice.load_order_group property for details. * Improve the error message displayed when the NT EventLog is full in response to feature request #643617. The EventLog output will now be disabled if any errors are encountered while logging events. This prevents the error from repeating. * Improve the error message displayed on Windows when the configured Java command can not be executed or does not exist. * Fix a problem where the Wrapper was leaving a pipe unclosed each time the JVM was restarted on all UNIX platforms. This was causing the Wrapper to run out of file handles. Bug #767267, discovered and patched by David Wong. * Fix a problem where the '#' character, which signifies a comment, could not be included in property values. A double hash, '##' will now resolve into a '#' within the property value. Bug #777303. * Added support for FreeBSD. Big thanks to Alphonse Bendt for supplying the patch. * Make the wrapper.port property optional. * Changed the way environment variables are loaded from the registry on Windows platforms so users will no longer get warning messages about not being able to handle very large environment variables. Prior versions could only handle environment variables whose expanded value was less than 2048 characters in length. * Fix a problem on UNIX platforms where a shell used to start the Wrapper running as a detached process would hang when the user attempted to exit the shell. Thanks to Mike Castle for this patch. 3.0.3 * Added support for Mac OS X. Big thanks to Andy Barnett for supplying the patch. * Fix a segmentation fault on UNIX systems when the first console output from the JVM was an empty line. Thanks to Mike Castle for finding this. * Fix a problem where a 0 length malloc was being called if there were no configured filters. This was fine on most platforms but caused a crash on MAC OS X. * Rework the initialization of the bash and sh scripts so that they will work correctly when referenced as symbolic links. Thanks go out to Richard Emberson for the code to resolve symbolic links. * Deprecated the realpath binary in the *NIX distributions as it is no longer used by the bash or sh scripts. It is being left in for now so as not to break the build scripts of other projects, but it will be removed after a couple more releases. * Added a test to make sure that wrapper.ntservice.interactive is not set to TRUE when an account is specified using wrapper.ntservice.account. 3.0.2 * Modified the sh and bash scripts so that console log output is disabled by default when the scripts are launched with the 'start' action. Running with the 'console' action will still send output to the console. Logging to the file is still enabled. * Modified the wrapper.ping.timeout property so it also controls the ping timeout within the JVM. Before the timeout on responses to the Wrapper could be controlled, but the ping timeout within the JVM was hardcoded to 30 seconds. * In the last release, some work was done to avoid false timeouts caused by large quantities of output. On some heavily loaded systems, timeouts were still being encountered. Rather than reading up to 50 lines of input, the code will now read for a maximum of 250ms before returning to give the main event loop more cycles. * Fix a problem where the values of environment variables set in the configuration file were not correct when those values included references to other environment variables. * Fix a potential buffer overflow problem if configuration properties referenced extremely large environment variables. * Fix a potential problem where the inability to expand very large environment variables would have led to an access violation when run as an NT service. * Add some extra checks in the event where the native library can not be loaded so that the WrapperManager can differentiate between the library missing and not being readable due to permission problems. * Remove the wrapper.ntservice.process_priority from the default wrapper.conf because its use can produce unexpected results if used improperly. Please see the property documentation for details. * Fix a problem where environment variables in the registry which had no value were causing the Wrapper to crash with an access violation. This was introduced in version 3.0.0 with the feature to load environment variables from the registry. The offending registry entry was WV_GATEWAY_CFG which appears to be related to Oracle. 3.0.1 * Fix a problem with the wrapper.disable_shutdown_hook. Due to a typo in the source, the property was being ignored. This was broken in the 3.0.0 release. * Fix a problem with the HP-UX release build reported by Ashish Gawarikar. * Add the ability to set environment variables from within the configuration file or from the command line. * Fix a problem on HP-UX and AIX machines where the stop() function in the shell scripts was causing a syntax error due to a conflict with a like named shell command on those platforms. This appears to be an issue with the Korn shell on all platforms. * Fix a problem where very heavy output from the JVM can cause the Wrapper to give a false timeout. The Wrapper now only reads 50 lines of input at a time to guarantee that the Wrapper's event loop always gets cycles. * Fix a problem on UNIX versions where extra line breaks would sometimes be added to the logged output when there was large amounts of output being sent from the JVM. * Fix a problem where a large number of calls to WrapperManager.log() immediately before the JVM exits could lead to the Wrapper incorrectly reporting that the JVM exited unexpectedly. 3.0.0 * Deprecated the com.silveregg.wrapper package in favor of org.tanukisoftware.wrapper. The classes and interfaces in the silveregg package will continue to function, but migration to the new package should be done when possible. See the project history for details. * On Windows systems change any forward slashes in the wrapper.java.command property to back slashes. Some users had reported having problems on Windows XP. * Implemented feature request #633178. Added WrapperManager.requestThreadDump() to force the current JVM to immediately perform a thread dump. * Fixed bug where wrapper.logfile.maxsize was being set to 0 if the 'k' or 'm' unit was omitted. * Add the ability to specify an account name and password when installing an NT service. * Add a property, wrapper.ntservice.interactive, which makes it possible to control whether or not the Java process can gain access to the desktop while it is running as an NT service. * Add limited support for 1.2.x versions of Java. Shutdown hooks are supported until Java 1.3 so those functions will be disabled. If the application displays a GUI then Java 1.3 should be used as the GUI can not currently be displayed when using Java 1.2.x. * Made it possible to use the wrapper.pidfile property on all *nix platforms. Please notice that the property has been removed from the default wrapper.conf file. The property is not needed when the wrapper is launched with the bash shell script. The sh shell script will set the wrapper.pidfile when the wrapper is launched. If either of the scripts provided with the Wrapper distribution are used then the wrapper.pidfile should always be removed from your wrapper.conf file. * Added a new wrapper.daemonize property which, when set, will form the wrapper process to be a detached non-session group leader. This makes it possible to launch the wrapper in such a way that it will not be terminated when the user launching the process logs out. This had been a problem on Solaris systems when using the sh shell. The default sh and bash scripts both make use of this in the default. Please update your scripts for use with this version. Thanks to Rajiv Subrahmanyam for the patch. * Fix a problem where the Wrapper was incorrectly counting the number of non-daemon threads in BEA's JRockit Virtual Machine. This was causing the application to shutdown when the non-daemon thread count dropped to 1. * Added support for building the wrapper on AIX and HP-UX systems. Thanks for the patches involved go out to Ashish Gawarikar and William Lee. * Implement feature request #653131 to force the JVM to immediately exit when the user presses CTRL-C multiple times. * Added a 'console' action to the bash and sh scripts to make it possible to launch the Wrapper in the current shell process. The 'start' task will launch the Wrapper as a spawned daemon process. * Fixed a problem where missing environment variables specified in classpath or library path properties were not being handled correctly. * Implemented feature request #676599 to enable the filtering of JVM output to trigger JVM restarts or Wrapper shutdowns. See the new wrapper.filter.trigger.n and wrapper.filter.action.n properties. * Modify the Win32 version of the Wrapper so that Environment Variables are always read from the system registry when the Wrapper is run as a service. By doing this, it makes it possible to change or add the system environment variables and have them take effect without having to first reboot the machine. * Implemented cascading configuration files. * Changed the default value for the wrapper.java.initmemory property to be 3Mb. The default on Windows and Linux JVMs is 2Mb, but the Solaris JVM requires a minimum of 3Mb. The minimum value accepted by the Wrapper was changed from 8Mb to 1Mb to make it possible to reduce the footprint of applications to what is possible without using the wrapper. * Improve the parsing of configuration files so that leading and trailing white space is now correctly trimmed. It is also now possible to have comments at the end of a line containing a property. * Modify the way exceptions thrown by an application's main method are presented to the user by the WrapperSimpleApp and WrapperStartStopApp so they no longer look like a problem with Wrapper configuration. 2.2.9 * Added a new property, wrapperper.restart.delay, which allows the user to control the amount of time to pause between a JVM exiting and a new JVM being launched. * Fixed bug #611024. The Wrapper would sometimes fail to start if wrapper.max_failed_invocations is set to 1. * Fix a problem where the number of non-daemon threads was not being calculated in some cases. * Implemented feature request #491443. Environment variables referenced in the wrapper.conf file will now be evaluated as the file is loaded. The windows syntax for environment variables is used on all platforms to make them platform independent. * Fixed a problem where the wrapper.conf was being open with both read and write locks when a read lock is all that is needed. Made the wrapper fail on startup if another application held a read lock on the conf file. * Modified the message displayed when the native library could not be found, so that it is much more descriptive. Hopefully it will cut down on questions caused by configuration problems. * Implemented feature request #613539. Modified the wrapper.java.library.path to function like the wrapper.java.classpath.n properties so that multiple directories can be specified in the library path in a platform independent way. The old property is still supported, but deprecated. * Fix Bug #632215. The WrapperManager.isLaunchedAsService() method was always returning false, even when run as a service under Windows. On linux, the Wrapper is always run as a console app, so this method will always return false. * Improve the message thrown when user code attempts to access System.in from within a JVM being controlled by the Wrapper. System.in will not work because the JVM is a spawned process. 2.2.8 * Fixed a compiler problem on Solaris some systems. * Added a new property, wrapper.cpu.timeout, which allows the user to control how much time without receiving any CPU the Wrapper will tolerate before displaying a warning message. The CPU timeout feature was added in 2.2.7 but the default timeout of 10 seconds was not configurable. * The Wrapper was only allowing 5 seconds between the JVM informing the Wrapper that it was going to exit and the JVM process actually exiting. This would cause the Wrapper to terminate the process prematurely in cases where an application shutdown thread took longer than 5 seconds to complete. The Wrapper now allows wrapper.jvm_exit.timeout seconds for the JVM process to exit on its own before being forcibly terminated. * When there is a configuration problem or a resource is unavailable, a JVM will sometimes exit abnormally very shortly after being launched. This can lead the the JVM being infinitely restarted due to a simple class path misconfiguration. To work around this, the Wrapper has always had a hard limit of 5 restarts within a short period of time. If the JVM has been running for more than a few minutes, then the count was reset. In this version, a new property. wrapper.max_failed_invocations was added to allow the max value to be set. The time period which the JVM must now be running for the JVM launch to have been considered a success for restart purposes is set using the new wrapper.successful_invocation_time property. * The number of advanced properties which most users do not need has been increasing as the Wrapper has been made more and more flexible. This has been causing confusion in their usage by people who play with them without first reading the documentation. To solve this, the advanced properties were removed from the default configuration file. They still function. But users must now read to the advanced configuration documentation to learn about their existence. Added quite about to the descriptions of these properties to hopefully clear up any confusion about their usage. * When the JVM exits abnormally, the Wrapper will pause for a few seconds before starting another JVM. If the user pressed CTRL-C during this pause, a new JVM would still be launched. The new JVM was exiting immediately but it was a waste of time. The Wrapper now recognizes the event and aborts launching the new JVM. * Added a page to the documentation which shows inline javadocs. This will hopefully make it easier to navigate them as part of the full documentation set. * Added a new method to the WrapperManager which enables user code to log at any log level. * Added a new Helper class WrapperStartStopApp which allows users to easily integrate applications like Tomcat which use a separate class to stop the application. * Added a samples section to the documentation. Just includes Tomcat 4 for now. 2.2.7 * Fix a problem where the JVM was trying to reconnect the Wrapper as it was being shutdown. This was causing problems if the JVM was being restarted. * Added support for the system being suspended to RAM or disk. Also improved wrapper performance when a system is under 100% load. See the new example output in the example section. * Fix a problem where the log output was not being directed to a file called wrapper.log in the same directory as the Wrapper binary in the event that the configured wrapper log file could not be accessed. * Fix a problem where the Wrapper was not shutting down the JVM correctly when all non daemon threads completed. Normally a JVM will exit when all of its non daemon threads have completed so this was causing some problems. (Thanks to Jung Tamas) * Added the ability to set the priority of the Wrapper and its JVM when run as an NT service or console application. The same thing can be better achieved on Unix systems by using "nice" in the shell script used to launch the Wrapper. See the documentation for for details. * JVM information was not being displayed correctly when the Wrapper native library could not be loaded. * Added a new property to cause the wrapper to attempt to request a thread dump when the JVM does not exit on request. * Improved the documentation of the WrapperSimpleApp and WrapperListener classes. * Adding a new property wrapper.shutdown.timeout to allow the user to extend the length of time that an application is allowed to take shutting down. * Rework the way the shutdown process works so that System.exit will never be called before the stop method in WrapperListener has had a chance to complete. * Add a Restart button to the TestWrapper application. * Fix a problem on Unix versions where '%' characters in Java output would sometimes cause the wrapper to crash. Somehow missed getting this into the last release. * Added a test to make sure that WrapperManager.stop is not called recursively. * Added support for building under Windows XP. Prebuilt installations had already been working. 2.2.6 * Fix a problem where '%' characters in Java output would sometimes cause the wrapper to crash. (Thanks to Frode Moe) * Added support for requesting a Java thread dump without shutting down the Java process. * Fixed a problem on windows where the java command was looking in the windows system and system32 directories for the java executable before checking the path when the full path to the java executable was not specified in the configuration file. This could lead to different JVM being run from the Wrapper than was run if java -version was run from the command line. The Wrapper will now attempt to resolve the full java path using the PATH environment variable. * Added debug output showing Java version information when the JVM first starts. * Modified c source to use /* */ style comments rather than // style comments. Some people were having problems with some compilers. 2.2.5 * Added support for service descriptions for Win2k and XP. * Fixed bug issue when reading configuration files from Windows on Unix. * Deprecated the wrapper.debug property in favor of loglevels. * Added new logger functionality includes the following features: Loglevels like Log4j, NT Eventlog support, UNIX syslog support and rolling log files. * Added wildcard support for classpath entries in wrapper.conf. * Added the ability to specify configuration properties from the command line. * Changed the way NT services are installed so that a patched version of the Wrapper.exe file no longer needs to be created to reference the wrapper.conf file. 2.2.4 * The value of APP_NAME in the bash or sh scripts no longer needs to be the same as the script. * Added the ability to format and/or disable file logging and output to the console. * Set mode of executables in binary release tar files so that they can be run without modification after being extracted. * Fixed line feeds in release so that bat files are always CRLF, unix scripts are always LF. Other source files are always CRLF in ZIP archives and LF in tar.gz archives. * Make the build fail if Wrapper.exe or Wrapper.dll do not exist for Windows builds. * Added an empty wrapper.log to the releases so that the TestWrapper example program runs out of the box. 2.2.3 * Added template scripts and conf files for ease of integration with other applications. * Cleaned up the build. * The WrapperSimpleApp method of launchine applications was not working correctly with applications whose main method did not return. * Add sample scripts and wrapper.conf files in the bin and lib directories. These scripts are used to start a sample application which runs out of the box. See the new example.html page in the documentation for more details. * Get rid of the platform specific directories in the bin and lib directories. * Enable relative paths for Windows version. In previous versions of Wrapper, it was necessary to always use absolute paths because the working directory of the wrapper would be then NT System32 directory when run as a service. * On the windows version, the wrapper always sets the current working directory to the location of the wrapper executable immediately after startup. * Improvements to the documentation / web page. 2.2.2 * Added HTML based documentation. 2.2.1 * Added Linux and Solaris build files. * Added Linux and Solaris documentation. 2.2.0 * Initial Public Release. wrapper_3.5.26_src/doc/wrapper-community-license-1.2.txt100644 0 0 47625 12440202301 20317 0ustar 0 0 ---------------------------------------------------------------------- ----------------- ----------------- Tanuki Software, Ltd. Community Software License Agreement Version 1.2 IMPORTANT-READ CAREFULLY: This license agreement is a legal agreement between you ("Licensee") and Tanuki Software, Ltd. ("TSI"), which includes computer software, associated media, printed materials, and may include online or electronic documentation ( Software ). PLEASE READ THIS AGREEMENT CAREFULLY BEFORE YOU INSTALL, COPY, DOWNLOAD OR USE THE SOFTWARE ACCOMPANYING THIS PACKAGE. Section 1 - Grant of License Community editions of the Software are made available on the GNU General Public License, Version 2 ("GPLv2"), included in Section 4 of this license document. All sections of the Community Software License Agreement must be complied with in addition to those of the GPLv2. Section 2 - Definitions 2.1. "Community Edition" shall mean versions of the Software Program distributed in source form under this license agreement, and all new releases, corrections, enhancements and updates to the Software Program, which TSI makes generally available under this agreement. 2.2. "Documentation" shall mean the contents of the website describing the functionality and use of the Software Program, located at http://wrapper.tanukisoftware.org 2.3. "Product" shall mean the computer programs, that are provided by Licensee to Licensee customers or potential customers, and that contain both the Software Program as a component of the Product, and a component or components (other than the Software Program) that provide the material functionality of the Product. If the Product is released in source form, the Software Program or any of its components may only be included in executable form. 2.4. "Software Program" shall mean the computer software and license file provided by TSI under this Agreement, including all new releases, corrections, enhancements and updates to such computer software, which TSI makes generally available and which Licensee receive pursuant to Licensee subscription to TSIMS. Some specific features or platforms may not be enabled if they do not fall under the feature set(s) covered by the specific license fees paid. 2.5 "End User" shall mean the customers of the Licensee or any recipient of the Product whether or not any payment is made to use the Product. Section 3 - Licensee Obligations A copy of this license must be distributed in full with the Product in a location that is obvious to any End User. In accordance with Section 4, the full source code of all components of the Product must be made available to any and all End Users. Licensee may extend and/or modify the Software Program and distribute under the terms of this agreement provided that the copyright notice and license information displayed in the console and log files are not obfuscated or obstructed in any way. Section 4 - GPLv2 License Agreement GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Section 4 - 3rd Party Components (1) The Software Program includes software and documentation components developed in part by Silver Egg Technology, Inc.("SET") prior to 2001 and released under the following license. Copyright (c) 2001 Silver Egg Technology Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub-license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. wrapper_3.5.26_src/src/bin/App.bat.in100644 0 0 10356 12440202300 14533 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general passthrough startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem _PASS_THROUGH tells the script to pass all parameters through to the JVM as rem is. rem set _PASS_THROUGH=true rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -c %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% -c %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/AppCommand.bat.in100644 0 0 13175 12440202300 16034 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper command based script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF="../conf/%_WRAPPER_BASE%.conf" rem _FIXED_COMMAND tells the script to use a hard coded command rather than rem expecting the first parameter of the command line to be the command. rem By default the command will will be expected to be the first parameter. rem set _FIXED_COMMAND=console rem _PASS_THROUGH tells the script to pass all parameters through to the JVM rem as is. If _FIXED_COMMAND is specified then all parameters will be passed. rem If not set then all parameters starting with the second will be passed. set _PASS_THROUGH=true rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof :conf if not [%_FIXED_COMMAND%]==[] ( set _COMMAND=%_FIXED_COMMAND% ) else ( set _COMMAND=%1 shift ) rem Collect all parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto parameters :callcommand rem rem Run the application. rem At runtime, the current directory will be that of wrapper.exe rem set _MATCHED=true if [%_COMMAND%]==[console] ( if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -c "%_WRAPPER_CONF%" %_PARAMETERS% ) else ( %_WRAPPER_EXE% -c "%_WRAPPER_CONF%" -- %_PARAMETERS% ) ) else if [%_COMMAND%]==[start] ( call :start ) else if [%_COMMAND%]==[stop] ( call :stop ) else if [%_COMMAND%]==[install] ( if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -i "%_WRAPPER_CONF%" %_PARAMETERS% ) else ( %_WRAPPER_EXE% -i "%_WRAPPER_CONF%" -- %_PARAMETERS% ) ) else if [%_COMMAND%]==[pause] ( %_WRAPPER_EXE% -a "%_WRAPPER_CONF%" ) else if [%_COMMAND%]==[resume] ( %_WRAPPER_EXE% -e "%_WRAPPER_CONF%" ) else if [%_COMMAND%]==[status] ( %_WRAPPER_EXE% -q "%_WRAPPER_CONF%" ) else if [%_COMMAND%]==[remove] ( %_WRAPPER_EXE% -r "%_WRAPPER_CONF%" ) else if [%_COMMAND%]==[restart] ( call :stop call :start ) else ( set _MATCHED= goto showusage ) if errorlevel 1 ( if [%_MATCHED%]==[] goto showusage ) goto :eof :showusage rem A command was not specified, or it was now known. if not [%_COMMAND%]==[] ( echo Unknown command: %_COMMAND% echo. ) if [%_PASS_THROUGH%]==[] ( echo Usage: %0 [ console : start : pause : resume : stop : restart : install : remove : status ] ) else ( echo Usage: %0 [ console {JavaAppArgs} : start : pause : resume : stop : restart : install {JavaAppArgs} : remove : status ] ) pause goto :eof :start %_WRAPPER_EXE% -t "%_WRAPPER_CONF%" goto :eof :stop %_WRAPPER_EXE% -p "%_WRAPPER_CONF%" goto :eof wrapper_3.5.26_src/src/bin/AppNoWrapper.bat.in100644 0 0 2032 12440202300 16341 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem This script is an example of how to run your application without the Wrapper, but with the rem Wrapper helper classes. You can obtain the actual command generated by the wrapper for rem your application by running the Wrapper with the wrapper.java.command.loglevel=INFO rem property set. rem rem The wrapper.key property MUST be removed from the resulting command or it will fail to rem run correctly. java -Xms16m -Xmx64m -Djava.library.path="../lib" -Djava.class.path="../lib/wrapper.jar;../lib/wrappertest.jar" -Dwrapper.native_library="wrapper" -Dwrapper.debug="TRUE" org.tanukisoftware.wrapper.test.Main wrapper_3.5.26_src/src/bin/AppTemplate.bat.in100644 0 0 10420 12440202300 16217 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem Note that it is only possible to pass parameters through to the JVM when rem installing the service, or when running in a console. rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% @wrapper.command@ %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% @wrapper.command@ %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/AppTemplatePassThrough.bat.in100644 0 0 10414 12440202300 20412 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general passthrough startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem _PASS_THROUGH tells the script to pass all parameters through to the JVM as rem is. rem set _PASS_THROUGH=true rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% @wrapper.command@ %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% @wrapper.command@ %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/InstallApp-NT.bat.in100644 0 0 10356 12440202300 16401 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general passthrough startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem _PASS_THROUGH tells the script to pass all parameters through to the JVM as rem is. rem set _PASS_THROUGH=true rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -i %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% -i %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/PauseApp-NT.bat.in100644 0 0 10362 12440202300 16045 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem Note that it is only possible to pass parameters through to the JVM when rem installing the service, or when running in a console. rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -a %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% -a %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/QueryApp-NT.bat.in100644 0 0 10362 12440202300 16075 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem Note that it is only possible to pass parameters through to the JVM when rem installing the service, or when running in a console. rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -q %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% -q %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/ResumeApp-NT.bat.in100644 0 0 10362 12440202300 16230 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem Note that it is only possible to pass parameters through to the JVM when rem installing the service, or when running in a console. rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -e %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% -e %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/StartApp-NT.bat.in100644 0 0 10362 12440202300 16065 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem Note that it is only possible to pass parameters through to the JVM when rem installing the service, or when running in a console. rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -t %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% -t %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/StopApp-NT.bat.in100644 0 0 10362 12440202300 15715 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem Note that it is only possible to pass parameters through to the JVM when rem installing the service, or when running in a console. rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -p %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% -p %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/UninstallApp-NT.bat.in100644 0 0 10362 12440202300 16741 0ustar 0 0 @echo off setlocal rem rem Copyright (c) 1999, 2014 Tanuki Software, Ltd. rem http://www.tanukisoftware.com rem All rights reserved. rem rem This software is the proprietary information of Tanuki Software. rem You shall use it only in accordance with the terms of the rem license agreement you entered into with Tanuki Software. rem http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html rem rem Java Service Wrapper general startup script. rem rem ----------------------------------------------------------------------------- rem These settings can be modified to fit the needs of your application rem Optimized for use with version 3.5.26 of the Wrapper. rem The base name for the Wrapper binary. set _WRAPPER_BASE=wrapper rem The directory where the Wrapper binary (.exe) file is located, this can be rem either a absolute or relative path. If the path contains any special characters, rem please make sure to quote the variable. set _WRAPPER_DIR= rem The name and location of the Wrapper configuration file. This will be used rem if the user does not specify a configuration file as the first parameter to rem this script. It will not be possible to specify a configuration file on the rem command line if _PASS_THROUGH is set. rem If a relative path is specified, please note that the location is based on the rem location. set _WRAPPER_CONF_DEFAULT="../conf/%_WRAPPER_BASE%.conf" rem Makes it possible to override the Wrapper configuration file by specifying it rem as the first parameter. rem set _WRAPPER_CONF_OVERRIDE=true rem Note that it is only possible to pass parameters through to the JVM when rem installing the service, or when running in a console. rem Do not modify anything beyond this point rem ----------------------------------------------------------------------------- rem rem Resolve the real path of the wrapper.exe rem For non NT systems, the _REALPATH and _WRAPPER_CONF values rem can be hard-coded below and the following test removed. rem if "%OS%"=="Windows_NT" goto nt echo This script only works with NT-based versions of Windows. goto :eof :nt rem Find the application home. rem if no path path specified do the default action IF not DEFINED _WRAPPER_DIR goto dir_undefined set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR:"=%" if not "%_WRAPPER_DIR:~-2,1%" == "\" set _WRAPPER_DIR_QUOTED="%_WRAPPER_DIR_QUOTED:"=%\" rem check if absolute path if "%_WRAPPER_DIR_QUOTED:~2,1%" == ":" goto absolute_path if "%_WRAPPER_DIR_QUOTED:~1,1%" == "\" goto absolute_path rem everythig else means relative path set _REALPATH="%~dp0%_WRAPPER_DIR_QUOTED:"=%" goto pathfound :dir_undefined rem Use a relative path to the wrapper %~dp0 is location of current script under NT set _REALPATH="%~dp0" goto pathfound :absolute_path rem Use an absolute path to the wrapper set _REALPATH="%_WRAPPER_DIR_QUOTED:"=%" :pathfound rem rem Decide on the specific Wrapper binary to use (See delta-pack) rem if "%PROCESSOR_ARCHITEW6432%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto amd64 if "%PROCESSOR_ARCHITECTURE%"=="IA64" goto ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-32.exe" goto search :amd64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-x86-64.exe" goto search :ia64 set _WRAPPER_L_EXE="%_REALPATH:"=%%_WRAPPER_BASE%-windows-ia-64.exe" goto search :search set _WRAPPER_EXE="%_WRAPPER_L_EXE:"=%" if exist %_WRAPPER_EXE% goto conf set _WRAPPER_EXE="%_REALPATH:"=%%_WRAPPER_BASE%.exe" if exist %_WRAPPER_EXE% goto conf echo Unable to locate a Wrapper executable using any of the following names: echo %_WRAPPER_L_EXE% echo %_WRAPPER_EXE% pause goto :eof rem rem Find the wrapper.conf rem :conf if not [%_WRAPPER_CONF_OVERRIDE%]==[] ( set _WRAPPER_CONF="%~f1" if not [%_WRAPPER_CONF%]==[""] ( shift goto :startup ) ) set _WRAPPER_CONF="%_WRAPPER_CONF_DEFAULT:"=%" rem rem Start the Wrapper rem :startup rem Collect an parameters :parameters set _PARAMETERS=%_PARAMETERS% %1 shift if not [%1]==[] goto :parameters if [%_PASS_THROUGH%]==[] ( %_WRAPPER_EXE% -r %_WRAPPER_CONF% ) else ( %_WRAPPER_EXE% -r %_WRAPPER_CONF% -- %_PARAMETERS% ) if not errorlevel 1 goto :eof pause wrapper_3.5.26_src/src/bin/sh.script.in100644 0 0 207514 12440202300 15207 0ustar 0 0 #! /bin/sh # # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html # # Java Service Wrapper sh script. Suitable for starting and stopping # wrapped Java applications on UNIX platforms. # #----------------------------------------------------------------------------- # These settings can be modified to fit the needs of your application # Optimized for use with version 3.5.26 of the Wrapper. # IMPORTANT - Please always stop and uninstall an application before making # any changes to this file. Failure to do so could remove the # script's ability to control the application. # Application APP_NAME="@app.name@" APP_LONG_NAME="@app.long.name@" # Wrapper WRAPPER_CMD="./wrapper" WRAPPER_CONF="../conf/wrapper.conf" # Priority at which to run the wrapper. See "man nice" for valid priorities. # nice is only used if a priority is specified. PRIORITY= # Location of the pid file. PIDDIR="." # PIDFILE_CHECK_PID tells the script to double check whether the pid in the pid # file actually exists and belongs to this application. When not set, only # check the pid, but not what it is. This is only needed when multiple # applications need to share the same pid file. PIDFILE_CHECK_PID=true # FIXED_COMMAND tells the script to use a hard coded action rather than # expecting the first parameter of the command line to be the command. # By default the command will will be expected to be the first parameter. #FIXED_COMMAND=console # PASS_THROUGH tells the script to pass all arguments through to the JVM # as is. If FIXED_COMMAND is specified then all arguments will be passed. # If not set then all arguments starting with the second will be passed. #PASS_THROUGH=true # If uncommented, causes the Wrapper to be shutdown using an anchor file. # When launched with the 'start' command, it will also ignore all INT and # TERM signals. #IGNORE_SIGNALS=true # Wrapper will start the JVM asynchronously. Your application may have some # initialization tasks and it may be desirable to wait a few seconds # before returning. For example, to delay the invocation of following # startup scripts. Setting WAIT_AFTER_STARTUP to a positive number will # cause the start command to delay for the indicated period of time # (in seconds). # WAIT_AFTER_STARTUP=0 # If set, wait for the wrapper to report that the daemon has started WAIT_FOR_STARTED_STATUS=true WAIT_FOR_STARTED_TIMEOUT=120 # If set, the status, start_msg and stop_msg commands will print out detailed # state information on the Wrapper and Java processes. #DETAIL_STATUS=true # If set, the 'pause' and 'resume' commands will be enabled. These make it # possible to pause the JVM or Java application without completely stopping # the Wrapper. See the wrapper.pausable and wrapper.pausable.stop_jvm # properties for more information. #PAUSABLE=true # If specified, the Wrapper will be run as the specified user. # IMPORTANT - Make sure that the user has the required privileges to write # the PID file and wrapper.log files. Failure to be able to write the log # file will cause the Wrapper to exit without any way to write out an error # message. # NOTE - This will set the user which is used to run the Wrapper as well as # the JVM and is not useful in situations where a privileged resource or # port needs to be allocated prior to the user being changed. #RUN_AS_USER= # Set the full path to the 'su' command (substitute user). # NOTE - In case 'su' is not in the PATH, you can set the absolute path here, # for example: # SU_BIN=/bin/su # NOTE - For Red Hat, the script will use '/sbin/runuser' if it is present and # ignore the value of SU_BIN. SU_BIN=su # Set option for 'su'. # In case the user set in RUN_AS_USER has no bash set, the 'su' command will fail. # The workaround for GNU/Linux system is to specify which bash to use with # the '-s' option. #SU_OPTS="-s /bin/bash" # By default we show a detailed usage block. Uncomment to show brief usage. #BRIEF_USAGE=true # OS service management tool: flag for using Upstart when installing (rather than init.d rc.d) USE_UPSTART= # OS service management tool: flag for using systemd when installing USE_SYSTEMD= # When installing on On Mac OSX platforms, the following domain will be used to # prefix the plist file name. PLIST_DOMAIN=org.tanukisoftware.wrapper # The following two lines are used by the chkconfig command. Change as is # appropriate for your application. They should remain commented. # chkconfig: 2345 20 80 # description: @app.long.name@ # Initialization block for the install_initd and remove_initd scripts used by # SUSE linux distributions. ### BEGIN INIT INFO # Provides: @app.name@ # Required-Start: $local_fs $network $syslog # Should-Start: # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: @app.long.name@ # Description: @app.description@ ### END INIT INFO # Set run level to use when installing the application to start and stop on # system startup and shutdown. It is important that the application always # be uninstalled before making any changes to the run levels. # It is also possible to specify different run levels based on the individual # platform. When doing so this script will look for defined run levels in # the following order: # 1) "RUN_LEVEL_S_$DIST_OS" or "RUN_LEVEL_K_$DIST_OS", where "$DIST_OS" is # the value of DIST_OS. "RUN_LEVEL_S_solaris=20" for example. # 2) RUN_LEVEL_S or RUN_LEVEL_K, to specify specify start or stop run levels. # 3) RUN_LEVEL, to specify a general run level. RUN_LEVEL=20 # Do not modify anything beyond this point #----------------------------------------------------------------------------- # check if we are running under Cygwin terminal. # Note: on some OS's (for example Solaris, MacOS), -o is not a valid parameter # and it shows an error message. We redirect stderr to null so the error message # doesn't show up. CYGWIN=`uname -o 2>/dev/null` if [ "$CYGWIN" = "Cygwin" ] then eval echo `gettext 'This script is not compatible with Cygwin. Please use the Wrapper batch files to control the Wrapper.'` exit 1 fi if [ -n "$FIXED_COMMAND" ] then COMMAND="$FIXED_COMMAND" else COMMAND="$1" fi # check if there is a parameter "sysd" SYSD= if [ $# -gt 1 ] ; then if [ $2 = "sysd" ] ; then SYSD=1 fi fi # default location for the service file SYSTEMD_SERVICE_FILE="/etc/systemd/system/$APP_NAME.service" # Required for HP-UX Startup if [ `uname -s` = "HP-UX" -o `uname -s` = "HP-UX64" ] ; then PATH=$PATH:/usr/bin fi # Get the fully qualified path to the script case $0 in /*) SCRIPT="$0" ;; *) PWD=`pwd` SCRIPT="$PWD/$0" ;; esac # Resolve the true real path without any sym links. CHANGED=true while [ "X$CHANGED" != "X" ] do # Change spaces to ":" so the tokens can be parsed. SAFESCRIPT=`echo $SCRIPT | sed -e 's; ;:;g'` # Get the real path to this script, resolving any symbolic links TOKENS=`echo $SAFESCRIPT | sed -e 's;/; ;g'` REALPATH= for C in $TOKENS; do # Change any ":" in the token back to a space. C=`echo $C | sed -e 's;:; ;g'` REALPATH="$REALPATH/$C" # If REALPATH is a sym link, resolve it. Loop for nested links. while [ -h "$REALPATH" ] ; do LS="`ls -ld "$REALPATH"`" LINK="`expr "$LS" : '.*-> \(.*\)$'`" if expr "$LINK" : '/.*' > /dev/null; then # LINK is absolute. REALPATH="$LINK" else # LINK is relative. REALPATH="`dirname "$REALPATH"`""/$LINK" fi done done if [ "$REALPATH" = "$SCRIPT" ] then CHANGED="" else SCRIPT="$REALPATH" fi done # Get the location of the script. REALDIR=`dirname "$REALPATH"` # Normalize the path REALDIR=`cd "${REALDIR}"; pwd` # If the PIDDIR is relative, set its value relative to the full REALPATH to avoid problems if # the working directory is later changed. FIRST_CHAR=`echo $PIDDIR | cut -c1,1` if [ "$FIRST_CHAR" != "/" ] then PIDDIR=$REALDIR/$PIDDIR fi # Same test for WRAPPER_CMD FIRST_CHAR=`echo $WRAPPER_CMD | cut -c1,1` if [ "$FIRST_CHAR" != "/" ] then WRAPPER_CMD=$REALDIR/$WRAPPER_CMD fi # Same test for WRAPPER_CONF FIRST_CHAR=`echo $WRAPPER_CONF | cut -c1,1` if [ "$FIRST_CHAR" != "/" ] then WRAPPER_CONF=$REALDIR/$WRAPPER_CONF fi # Process ID ANCHORFILE="$PIDDIR/$APP_NAME.anchor" COMMANDFILE="$PIDDIR/$APP_NAME.command" STATUSFILE="$PIDDIR/$APP_NAME.status" JAVASTATUSFILE="$PIDDIR/$APP_NAME.java.status" PIDFILE="$PIDDIR/$APP_NAME.pid" LOCKDIR="/var/lock/subsys" LOCKFILE="$LOCKDIR/$APP_NAME" pid="" # Resolve the location of the 'ps' command PS_BIN="/usr/ucb/ps" if [ ! -x "$PS_BIN" ] then PS_BIN="/usr/bin/ps" if [ ! -x "$PS_BIN" ] then PS_BIN="/bin/ps" if [ ! -x "$PS_BIN" ] then eval echo `gettext 'Unable to locate "ps".'` eval echo `gettext 'Please report this message along with the location of the command on your system.'` exit 1 fi fi fi TR_BIN="/usr/bin/tr" if [ ! -x "$TR_BIN" ] then TR_BIN="/bin/tr" if [ ! -x "$TR_BIN" ] then eval echo `gettext 'Unable to locate "tr".'` eval echo `gettext 'Please report this message along with the location of the command on your system.'` exit 1 fi fi # Resolve the os DIST_OS=`uname -s | $TR_BIN "[A-Z]" "[a-z]" | $TR_BIN -d ' '` case "$DIST_OS" in 'sunos') DIST_OS="solaris" ;; 'hp-ux' | 'hp-ux64') # HP-UX needs the XPG4 version of ps (for -o args) DIST_OS="hpux" UNIX95="" export UNIX95 ;; 'darwin') DIST_OS="macosx" ;; 'unix_sv') DIST_OS="unixware" ;; 'os/390') DIST_OS="zos" ;; esac # Compare Versions $1<$2=0, $1==$2=1, $1>$2=2 compareVersions () { if [ "$1" = "$2" ] then return 1 else local i=1 while true do local v1=`echo "$1" | cut -d '.' -f $i` local v2=`echo "$2" | cut -d '.' -f $i` if [ "X$v1" = "X" ] then if [ "X$v2" = "X" ] then return 1 fi v1="0" elif [ "X$v2" = "X" ] then v2="0" fi if [ $v1 -lt $v2 ] then return 0 elif [ $v1 -gt $v2 ] then return 2 fi i=`expr $i + 1` done fi } # Resolve the architecture if [ "$DIST_OS" = "macosx" ] then OS_VER=`sw_vers | grep 'ProductVersion:' | grep -o '[0-9]*\.[0-9]*\.[0-9]*\|[0-9]*\.[0-9]*'` DIST_ARCH="universal" compareVersions "$OS_VER" "10.5.0" if [[ $? < 1 ]] then DIST_BITS="32" KEY_KEEP_ALIVE="OnDemand" else KEY_KEEP_ALIVE="KeepAlive" if [ "X`/usr/sbin/sysctl -n hw.cpu64bit_capable`" == "X1" ] then DIST_BITS="64" else DIST_BITS="32" fi fi APP_PLIST_BASE=${PLIST_DOMAIN}.${APP_NAME} APP_PLIST=${APP_PLIST_BASE}.plist else if [ "$DIST_OS" = "linux" ] then DIST_ARCH= else DIST_ARCH=`uname -p 2>/dev/null | $TR_BIN "[A-Z]" "[a-z]" | $TR_BIN -d ' '` fi if [ "X$DIST_ARCH" = "X" ] then DIST_ARCH="unknown" fi if [ "$DIST_ARCH" = "unknown" ] then DIST_ARCH=`uname -m 2>/dev/null | $TR_BIN "[A-Z]" "[a-z]" | $TR_BIN -d ' '` fi case "$DIST_ARCH" in 'athlon' | 'i386' | 'i486' | 'i586' | 'i686') DIST_ARCH="x86" if [ "${DIST_OS}" = "solaris" ] ; then DIST_BITS=`isainfo -b` else DIST_BITS="32" fi ;; 'amd64' | 'x86_64') DIST_ARCH="x86" DIST_BITS="64" ;; 'ia32') DIST_ARCH="ia" DIST_BITS="32" ;; 'ia64' | 'ia64n' | 'ia64w') DIST_ARCH="ia" DIST_BITS="64" ;; 'ip27') DIST_ARCH="mips" DIST_BITS="32" ;; 'power' | 'powerpc' | 'power_pc' | 'ppc64') if [ "${DIST_ARCH}" = "ppc64" ] ; then DIST_BITS="64" else DIST_BITS="32" fi DIST_ARCH="ppc" if [ "${DIST_OS}" = "aix" ] ; then if [ `getconf KERNEL_BITMODE` -eq 64 ]; then DIST_BITS="64" else DIST_BITS="32" fi fi ;; 'pa_risc' | 'pa-risc') DIST_ARCH="parisc" if [ `getconf KERNEL_BITS` -eq 64 ]; then DIST_BITS="64" else DIST_BITS="32" fi ;; 'sun4u' | 'sparcv9' | 'sparc') DIST_ARCH="sparc" DIST_BITS=`isainfo -b` ;; '9000/800' | '9000/785') DIST_ARCH="parisc" if [ `getconf KERNEL_BITS` -eq 64 ]; then DIST_BITS="64" else DIST_BITS="32" fi ;; '2064' | '2066' | '2084' | '2086' | '2094' | '2096' | '2097' | '2098' | '2817') DIST_ARCH="390" DIST_BITS="64" ;; armv*) if [ -z "`readelf -A /proc/self/exe | grep Tag_ABI_VFP_args`" ] ; then DIST_ARCH="armel" DIST_BITS="32" else DIST_ARCH="armhf" DIST_BITS="32" fi ;; esac fi # OSX always places Java in the same location so we can reliably set JAVA_HOME if [ "$DIST_OS" = "macosx" ] then if [ -z "$JAVA_HOME" ]; then if [ -x /usr/libexec/java_home ]; then JAVA_HOME=`/usr/libexec/java_home`; export JAVA_HOME else JAVA_HOME="/Library/Java/Home"; export JAVA_HOME fi fi fi # Test Echo ECHOTEST=`echo -n "x"` if [ "$ECHOTEST" = "x" ] then ECHOOPT="-n " else ECHOOPT="" fi gettext() { "$WRAPPER_CMD" --translate "$1" "$WRAPPER_CONF" 2>/dev/null if [ $? != 0 ] ; then echo "$1" fi } outputFile() { if [ -f "$1" ] then eval echo `gettext ' $1 Found but not executable.'`; else echo " $1" fi } # Decide on the wrapper binary to use. # If the bits of the OS could be detected, we will try to look for the # binary with the correct bits value. If it doesn't exist, fall back # and look for the 32-bit binary. If that doesn't exist either then # look for the default. WRAPPER_TEST_CMD="" if [ -f "$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-$DIST_BITS" ] then WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-$DIST_BITS" if [ ! -x "$WRAPPER_TEST_CMD" ] then chmod +x "$WRAPPER_TEST_CMD" 2>/dev/null fi if [ -x "$WRAPPER_TEST_CMD" ] then WRAPPER_CMD="$WRAPPER_TEST_CMD" else outputFile "$WRAPPER_TEST_CMD" WRAPPER_TEST_CMD="" fi fi if [ -f "$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-32" -a -z "$WRAPPER_TEST_CMD" ] then WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-32" if [ ! -x "$WRAPPER_TEST_CMD" ] then chmod +x "$WRAPPER_TEST_CMD" 2>/dev/null fi if [ -x "$WRAPPER_TEST_CMD" ] then WRAPPER_CMD="$WRAPPER_TEST_CMD" else outputFile "$WRAPPER_TEST_CMD" WRAPPER_TEST_CMD="" fi fi if [ -f "$WRAPPER_CMD" -a -z "$WRAPPER_TEST_CMD" ] then WRAPPER_TEST_CMD="$WRAPPER_CMD" if [ ! -x "$WRAPPER_TEST_CMD" ] then chmod +x "$WRAPPER_TEST_CMD" 2>/dev/null fi if [ -x "$WRAPPER_TEST_CMD" ] then WRAPPER_CMD="$WRAPPER_TEST_CMD" else outputFile "$WRAPPER_TEST_CMD" WRAPPER_TEST_CMD="" fi fi if [ -z "$WRAPPER_TEST_CMD" ] then eval echo `gettext 'Unable to locate any of the following binaries:'` outputFile "$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-$DIST_BITS" if [ ! "$DIST_BITS" = "32" ] then outputFile "$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-32" fi outputFile "$WRAPPER_CMD" exit 1 fi # Build the nice clause if [ "X$PRIORITY" = "X" ] then CMDNICE="" else CMDNICE="nice -$PRIORITY" fi # Build the anchor file clause. if [ "X$IGNORE_SIGNALS" = "X" ] then ANCHORPROP= IGNOREPROP= else ANCHORPROP=wrapper.anchorfile=\"$ANCHORFILE\" IGNOREPROP=wrapper.ignore_signals=TRUE fi # Build the status file clause. if [ "X$DETAIL_STATUS$WAIT_FOR_STARTED_STATUS" = "X" ] then STATUSPROP= else STATUSPROP="wrapper.statusfile=\"$STATUSFILE\" wrapper.java.statusfile=\"$JAVASTATUSFILE\"" fi # Build the command file clause. if [ -n "$PAUSABLE" ] then COMMANDPROP="wrapper.commandfile=\"$COMMANDFILE\" wrapper.pausable=TRUE" else COMMANDPROP= fi if [ ! -n "$WAIT_FOR_STARTED_STATUS" ] then WAIT_FOR_STARTED_STATUS=true fi if [ $WAIT_FOR_STARTED_STATUS = true ] ; then DETAIL_STATUS=true fi # Build the lock file clause. Only create a lock file if the lock directory exists on this platform. LOCKPROP= if [ -d $LOCKDIR ] then if [ -w $LOCKDIR ] then LOCKPROP=wrapper.lockfile=\"$LOCKFILE\" fi fi # Decide on run levels. RUN_LEVEL_S_DIST_OS_TMP=`eval "echo \$\{RUN_LEVEL_S_${DIST_OS}\}"` RUN_LEVEL_S_DIST_OS=`eval "echo ${RUN_LEVEL_S_DIST_OS_TMP}"` if [ "X${RUN_LEVEL_S_DIST_OS}" != "X" ] ; then APP_RUN_LEVEL_S=${RUN_LEVEL_S_DIST_OS} elif [ "X$RUN_LEVEL_S" != "X" ] ; then APP_RUN_LEVEL_S=$RUN_LEVEL_S else APP_RUN_LEVEL_S=$RUN_LEVEL fi APP_RUN_LEVEL_S_CHECK=`echo "$APP_RUN_LEVEL_S" | sed "s/[(0-9)*]/0/g"` if [ "X${APP_RUN_LEVEL_S_CHECK}" != "X00" ] ; then eval echo `gettext 'Run level \"${APP_RUN_LEVEL_S}\" must be numeric and have a length of two \(00-99\).'` exit 1; fi RUN_LEVEL_K_DIST_OS_TMP=`eval "echo \$\{RUN_LEVEL_K_${DIST_OS}\}"` RUN_LEVEL_K_DIST_OS=`eval "echo ${RUN_LEVEL_K_DIST_OS_TMP}"` if [ "X${RUN_LEVEL_K_DIST_OS}" != "X" ] ; then APP_RUN_LEVEL_K=${RUN_LEVEL_K_DIST_OS} elif [ "X$RUN_LEVEL_K" != "X" ] ; then APP_RUN_LEVEL_K=$RUN_LEVEL_K else APP_RUN_LEVEL_K=$RUN_LEVEL fi APP_RUN_LEVEL_K_CHECK=`echo "$APP_RUN_LEVEL_K" | sed "s/[(0-9)*]/0/g"` if [ "X${APP_RUN_LEVEL_K_CHECK}" != "X00" ] ; then eval echo `gettext 'Run level \"${APP_RUN_LEVEL_K}\" must be numeric and have a length of two \(00-99\).'` exit 1; fi prepAdditionalParams() { ADDITIONAL_PARA="" if [ -n "$PASS_THROUGH" ] ; then ADDITIONAL_PARA="--" fi while [ -n "$1" ] ; do ADDITIONAL_PARA="$ADDITIONAL_PARA \"$1\"" shift done } checkUser() { # $1 touchLock flag # $2.. [command] args # Check the configured user. If necessary rerun this script as the desired user. if [ "X$RUN_AS_USER" != "X" ] then # Resolve the location of the 'id' command ID_BIN="/usr/xpg4/bin/id" if [ ! -x "$ID_BIN" ] then ID_BIN="/usr/bin/id" if [ ! -x "$ID_BIN" ] then eval echo `gettext 'Unable to locate "id".'` eval echo `gettext 'Please report this message along with the location of the command on your system.'` exit 1 fi fi if [ "`$ID_BIN -u -n`" = "$RUN_AS_USER" ] then # Already running as the configured user. Avoid password prompts by not calling su. RUN_AS_USER="" fi fi if [ "X$RUN_AS_USER" != "X" ] then if [ "`$ID_BIN -u -n "$RUN_AS_USER" 2>/dev/null`" != "$RUN_AS_USER" ] then eval echo `gettext 'User $RUN_AS_USER does not exist.'` exit 1 fi # If LOCKPROP and $RUN_AS_USER are defined then the new user will most likely not be # able to create the lock file. The Wrapper will be able to update this file once it # is created but will not be able to delete it on shutdown. If $1 is set then # the lock file should be created for the current command if [ "X$LOCKPROP" != "X" ] then if [ "X$1" != "X" ] then # Resolve the primary group RUN_AS_GROUP=`groups $RUN_AS_USER | awk '{print $3}' | tail -1` if [ "X$RUN_AS_GROUP" = "X" ] then RUN_AS_GROUP=$RUN_AS_USER fi touch $LOCKFILE chown $RUN_AS_USER:$RUN_AS_GROUP $LOCKFILE fi fi # Still want to change users, recurse. This means that the user will only be # prompted for a password once. Variables shifted by 1 shift # Wrap the parameters so they can be passed. ADDITIONAL_PARA="" while [ -n "$1" ] ; do ADDITIONAL_PARA="$ADDITIONAL_PARA \"$1\"" shift done # Use "runuser" if this exists. runuser should be used on RedHat in preference to su. # if test -f "/sbin/runuser" then /sbin/runuser - $RUN_AS_USER -c "\"$REALPATH\" $ADDITIONAL_PARA" else $SU_BIN - $RUN_AS_USER -c "\"$REALPATH\" $ADDITIONAL_PARA" $SU_OPTS fi RUN_AS_USER_EXITCODE=$? # we check if the previous command has failed if [ $RUN_AS_USER_EXITCODE -ne 0 ] then eval echo `gettext 'Could not run the command using user \"$RUN_AS_USER\".'` eval echo `gettext 'Advice: Make sure the user \"$RUN_AS_USER\" has a shell.'` eval echo `gettext ' If user \"$RUN_AS_USER\" has a no shell, you can specify one using SU_OPTS if your platform support it.'` eval echo `gettext ' For example, at the top of this script you can set: SU_OPTS=\"-s /bin/bash\".'` eval echo `gettext ' Another workaround would be to use a OS service management tool if available on your platform.'` eval echo `gettext ' OS service management tools supported by this script are described at the top of this script.'` fi # Now that we are the original user again, we may need to clean up the lock file. if [ "X$LOCKPROP" != "X" ] then getpid if [ "X$pid" = "X" ] then # Wrapper is not running so make sure the lock file is deleted. if [ -f "$LOCKFILE" ] then rm "$LOCKFILE" fi fi fi exit $RUN_AS_USER_EXITCODE fi } getpid() { pid="" if [ -f "$PIDFILE" ] then if [ -r "$PIDFILE" ] then pid=`cat "$PIDFILE"` if [ "X$pid" != "X" ] then if [ "X$PIDFILE_CHECK_PID" != "X" ] then # It is possible that 'a' process with the pid exists but that it is not the # correct process. This can happen in a number of cases, but the most # common is during system startup after an unclean shutdown. # The ps statement below looks for the specific wrapper command running as # the pid. If it is not found then the pid file is considered to be stale. case "$DIST_OS" in 'freebsd') pidtest=`$PS_BIN -p $pid -o args | tail -1` if [ "X$pidtest" = "XCOMMAND" ] then pidtest="" fi ;; 'macosx') pidtest=`$PS_BIN -ww -p $pid -o command | grep -F "$WRAPPER_CMD" | tail -1` ;; 'solaris') if [ -f "/usr/bin/pargs" ] then pidtest=`pargs $pid | fgrep "$WRAPPER_CMD" | tail -1` else case "$PS_BIN" in '/usr/ucb/ps') pidtest=`$PS_BIN -auxww $pid | fgrep "$WRAPPER_CMD" | tail -1` ;; '/usr/bin/ps') TRUNCATED_CMD=`$PS_BIN -o comm -p $pid | tail -1` COUNT=`echo $TRUNCATED_CMD | wc -m` COUNT=`echo ${COUNT}` COUNT=`expr $COUNT - 1` TRUNCATED_CMD=`echo $WRAPPER_CMD | cut -c1-$COUNT` pidtest=`$PS_BIN -o comm -p $pid | fgrep "$TRUNCATED_CMD" | tail -1` ;; '/bin/ps') TRUNCATED_CMD=`$PS_BIN -o comm -p $pid | tail -1` COUNT=`echo $TRUNCATED_CMD | wc -m` COUNT=`echo ${COUNT}` COUNT=`expr $COUNT - 1` TRUNCATED_CMD=`echo $WRAPPER_CMD | cut -c1-$COUNT` pidtest=`$PS_BIN -o comm -p $pid | fgrep "$TRUNCATED_CMD" | tail -1` ;; *) echo "Unsupported ps command $PS_BIN" exit 1 ;; esac fi ;; 'hpux') pidtest=`$PS_BIN -p $pid -x -o args | grep -F "$WRAPPER_CMD" | tail -1` ;; *) pidtest=`$PS_BIN -p $pid -o args | grep -F "$WRAPPER_CMD" | tail -1` ;; esac else # Check to see whether the pid exists as a running process, but in this mode, don't check what that pid is. case "$DIST_OS" in 'solaris') case "$PS_BIN" in '/usr/ucb/ps') pidtest=`$PS_BIN $pid | grep "$pid" | awk '{print $1}' | tail -1` ;; '/usr/bin/ps') pidtest=`$PS_BIN -p $pid -o pid | grep "$pid" | tail -1` ;; '/bin/ps') pidtest=`$PS_BIN -p $pid -o pid | grep "$pid" | tail -1` ;; *) echo "Unsupported ps command $PS_BIN" exit 1 ;; esac ;; *) pidtest=`$PS_BIN -p $pid -o pid | grep "$pid" | tail -1` ;; esac fi if [ "X$pidtest" = "X" ] then # This is a stale pid file. rm -f "$PIDFILE" eval echo `gettext 'Removed stale pid file: $PIDFILE'` pid="" fi fi else eval echo `gettext 'Cannot read $PIDFILE.'` exit 1 fi fi } getstatus() { STATUS= if [ -f "$STATUSFILE" ] then if [ -r "$STATUSFILE" ] then STATUS=`cat "$STATUSFILE"` fi fi if [ "X$STATUS" = "X" ] then STATUS="Unknown" fi JAVASTATUS= if [ -f "$JAVASTATUSFILE" ] then if [ -r "$JAVASTATUSFILE" ] then JAVASTATUS=`cat "$JAVASTATUSFILE"` fi fi if [ "X$JAVASTATUS" = "X" ] then JAVASTATUS="Unknown" fi } testpid() { case "$DIST_OS" in 'solaris') case "$PS_BIN" in '/usr/ucb/ps') pid=`$PS_BIN $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1` ;; '/usr/bin/ps') pid=`$PS_BIN -p $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1` ;; '/bin/ps') pid=`$PS_BIN -p $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1` ;; *) echo "Unsupported ps command $PS_BIN" exit 1 ;; esac ;; *) pid=`$PS_BIN -p $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1` 2>/dev/null ;; esac if [ "X$pid" = "X" ] then # Process is gone so remove the pid file. rm -f "$PIDFILE" pid="" fi } launchdtrap() { stopit exit } waitforwrapperstop() { getpid while [ "X$pid" != "X" ] ; do sleep 1 getpid done } launchinternal() { getpid trap launchdtrap TERM if [ "X$pid" = "X" ] then prepAdditionalParams "$@" # The string passed to eval must handles spaces in paths correctly. COMMAND_LINE="$CMDNICE \"$WRAPPER_CMD\" \"$WRAPPER_CONF\" wrapper.syslog.ident=\"$APP_NAME\" wrapper.pidfile=\"$PIDFILE\" wrapper.name=\"$APP_NAME\" wrapper.displayname=\"$APP_LONG_NAME\" wrapper.daemonize=TRUE $ANCHORPROP $IGNOREPROP $STATUSPROP $COMMANDPROP $LOCKPROP wrapper.script.version=3.5.26 $ADDITIONAL_PARA" eval $COMMAND_LINE else eval echo `gettext '$APP_LONG_NAME is already running.'` exit 1 fi # launchd expects that this script stay up and running so we need to do our own monitoring of the Wrapper process. if [ $WAIT_FOR_STARTED_STATUS = true ] then waitforwrapperstop fi } console() { eval echo `gettext 'Running $APP_LONG_NAME...'` getpid if [ "X$pid" = "X" ] then trap '' 3 prepAdditionalParams "$@" # The string passed to eval must handles spaces in paths correctly. COMMAND_LINE="$CMDNICE \"$WRAPPER_CMD\" \"$WRAPPER_CONF\" wrapper.syslog.ident=\"$APP_NAME\" wrapper.pidfile=\"$PIDFILE\" wrapper.name=\"$APP_NAME\" wrapper.displayname=\"$APP_LONG_NAME\" $ANCHORPROP $STATUSPROP $COMMANDPROP $LOCKPROP wrapper.script.version=3.5.26 $ADDITIONAL_PARA" eval $COMMAND_LINE else eval echo `gettext '$APP_LONG_NAME is already running.'` exit 1 fi } waitforjavastartup() { getstatus eval echo $ECHOOPT `gettext 'Waiting for $APP_LONG_NAME...'` # Wait until the timeout or we have something besides Unknown. counter=15 while [ "$JAVASTATUS" = "Unknown" -a $counter -gt 0 -a -n "$JAVASTATUS" ] ; do echo $ECHOOPT"." sleep 1 getstatus counter=`expr $counter - 1` done if [ -n "$WAIT_FOR_STARTED_TIMEOUT" ] ; then counter=$WAIT_FOR_STARTED_TIMEOUT else counter=120 fi while [ "$JAVASTATUS" != "STARTED" -a "$JAVASTATUS" != "Unknown" -a $counter -gt 0 -a -n "$JAVASTATUS" ] ; do echo $ECHOOPT"." sleep 1 getstatus counter=`expr $counter - 1` done if [ "X$ECHOOPT" != "X" ] ; then echo "" fi } startwait() { if [ $WAIT_FOR_STARTED_STATUS = true ] then waitforjavastartup fi # Sleep for a few seconds to allow for intialization if required # then test to make sure we're still running. # i=0 while [ $i -lt $WAIT_AFTER_STARTUP ] do sleep 1 echo $ECHOOPT"." i=`expr $i + 1` done if [ $WAIT_AFTER_STARTUP -gt 0 -o $WAIT_FOR_STARTED_STATUS = true ] then getpid if [ "X$pid" = "X" ] then eval echo `gettext ' WARNING: $APP_LONG_NAME may have failed to start.'` exit 1 else eval echo `gettext ' running: PID:$pid'` fi else echo "" fi } mustBeRootOrExit() { if [ `id | sed 's/^uid=//;s/(.*$//'` != "0" ] ; then eval echo `gettext 'Must be root to perform this action.'` exit 1 fi } macosxStart() { # The daemon has been installed. eval echo `gettext 'Starting $APP_LONG_NAME. Detected Mac OSX and installed launchd daemon.'` mustBeRootOrExit getpid if [ "X$pid" != "X" ] ; then eval echo `gettext '$APP_LONG_NAME is already running.'` exit 1 fi # If the daemon was just installed, it may not be loaded. LOADED_PLIST=`launchctl list | grep ${APP_PLIST_BASE}` if [ "X${LOADED_PLIST}" = "X" ] ; then launchctl load /Library/LaunchDaemons/${APP_PLIST} fi # If launchd is set to run the daemon already at Load, we don't need to call start getpid if [ "X$pid" = "X" ] ; then launchctl start ${APP_PLIST_BASE} fi startwait } macosxStop() { # The daemon should be running. eval echo `gettext 'Stopping $APP_LONG_NAME...'` mustBeRootOrExit getpid if [ "X$pid" = "X" ] ; then eval echo `gettext '$APP_LONG_NAME is not running.'` exit 1 else launchctl stop ${APP_PLIST_BASE} fi } macosxRestart() { # The daemon should be running. eval echo `gettext 'Restarting $APP_LONG_NAME...'` mustBeRootOrExit getpid if [ "X$pid" = "X" ] ; then eval echo `gettext '$APP_LONG_NAME is not running.'` exit 1 else launchctl unload "/Library/LaunchDaemons/${APP_PLIST}" launchctl load "/Library/LaunchDaemons/${APP_PLIST}" fi startwait } upstartstart() { # The daemon has been installed. eval echo `gettext 'Starting $APP_LONG_NAME. Detected Linux and installed upstart.'` mustBeRootOrExit getpid if [ "X$pid" != "X" ] ; then eval echo `gettext '$APP_LONG_NAME is already running.'` exit 1 fi /sbin/start ${APP_NAME} startwait } upstartStop() { # The daemon has been installed. eval echo `gettext 'Stopping $APP_LONG_NAME...'` mustBeRootOrExit getpid if [ "X$pid" = "X" ] ; then eval echo `gettext '$APP_LONG_NAME is not running.'` exit 1 fi /sbin/stop ${APP_NAME} } upstartRestart() { # The daemon has been installed. eval echo `gettext 'Restarting $APP_LONG_NAME...'` mustBeRootOrExit getpid if [ "X$pid" = "X" ] ; then eval echo `gettext '$APP_LONG_NAME is not running.'` exit 1 fi /sbin/restart ${APP_NAME} startwait } systemdInstall() { eval echo `gettext ' Installing the $APP_LONG_NAME daemon using systemd...'` if [ -f "${REALDIR}/${APP_NAME}.service" ] ; then eval echo `gettext ' a custom service file ${APP_NAME}.service found'` cp "${REALDIR}/${APP_NAME}.service" "${SYSTEMD_SERVICE_FILE}" else eval echo `gettext ' creating default service file...'` echo "[Unit]" > "${SYSTEMD_SERVICE_FILE}" echo "Description=${APP_LONG_NAME}" >> "${SYSTEMD_SERVICE_FILE}" echo "After=syslog.target" >> "${SYSTEMD_SERVICE_FILE}" echo "" >> "${SYSTEMD_SERVICE_FILE}" echo "[Service]" >> "${SYSTEMD_SERVICE_FILE}" echo "Type=forking" >> "${SYSTEMD_SERVICE_FILE}" echo "ExecStart=${REALPATH} start sysd" >> "${SYSTEMD_SERVICE_FILE}" echo "ExecStop=${REALPATH} stop sysd" >> "${SYSTEMD_SERVICE_FILE}" echo "" >> "${SYSTEMD_SERVICE_FILE}" echo "[Install]" >> "${SYSTEMD_SERVICE_FILE}" echo "WantedBy=multi-user.target" >> "${SYSTEMD_SERVICE_FILE}" systemctl daemon-reload systemctl enable "${APP_NAME}" fi } systemdStart() { # check if the service file is present if [ -f "${SYSTEMD_SERVICE_FILE}" ] ; then eval echo `gettext 'Reading file ${SYSTEMD_SERVICE_FILE}'` else eval echo `gettext 'No service file detected. Did you install the service?'` exit 1 fi systemctl start $APP_NAME if [ $? -ne 0 ] ; then eval echo `gettext 'Failed to start service $APP_NAME'` exit 1 fi startwait } systemdStop() { systemctl stop $APP_NAME if [ $? -ne 0 ] ; then eval echo `gettext 'Failed to stop $APP_NAME'` exit 1 fi } systemdRestart() { systemctl restart $APP_NAME if [ $? -ne 0 ] ; then eval echo `gettext 'Failed to restart $APP_NAME'` exit 1 fi startwait } systemdRemove() { stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon from systemd...'` systemctl disable $APP_NAME rm "/etc/systemd/system/${APP_NAME}.service" systemctl daemon-reload } start() { eval echo `gettext 'Starting $APP_LONG_NAME...'` getpid if [ "X$pid" = "X" ] then prepAdditionalParams "$@" # The string passed to eval must handles spaces in paths correctly. COMMAND_LINE="$CMDNICE \"$WRAPPER_CMD\" \"$WRAPPER_CONF\" wrapper.syslog.ident=\"$APP_NAME\" wrapper.pidfile=\"$PIDFILE\" wrapper.name=\"$APP_NAME\" wrapper.displayname=\"$APP_LONG_NAME\" wrapper.daemonize=TRUE $ANCHORPROP $IGNOREPROP $STATUSPROP $COMMANDPROP $LOCKPROP wrapper.script.version=3.5.26 $ADDITIONAL_PARA" eval $COMMAND_LINE else eval echo `gettext '$APP_LONG_NAME is already running.'` exit 1 fi startwait } stopit() { # $1 exit if down flag eval echo `gettext 'Stopping $APP_LONG_NAME...'` getpid if [ "X$pid" = "X" ] then eval echo `gettext '$APP_LONG_NAME was not running.'` if [ "X$1" = "X1" ] then exit 1 fi else if [ "X$IGNORE_SIGNALS" = "X" ] then # Running so try to stop it. kill $pid if [ $? -ne 0 ] then # An explanation for the failure should have been given eval echo `gettext 'Unable to stop $APP_LONG_NAME.'` exit 1 fi else rm -f "$ANCHORFILE" if [ -f "$ANCHORFILE" ] then # An explanation for the failure should have been given eval echo `gettext 'Unable to stop $APP_LONG_NAME.'` exit 1 fi fi # We can not predict how long it will take for the wrapper to # actually stop as it depends on settings in wrapper.conf. # Loop until it does. savepid=$pid CNT=0 TOTCNT=0 while [ "X$pid" != "X" ] do # Show a waiting message every 5 seconds. if [ "$CNT" -lt "5" ] then CNT=`expr $CNT + 1` else eval echo `gettext 'Waiting for $APP_LONG_NAME to exit...'` CNT=0 fi TOTCNT=`expr $TOTCNT + 1` sleep 1 testpid done pid=$savepid testpid if [ "X$pid" != "X" ] then eval echo `gettext 'Failed to stop $APP_LONG_NAME.'` exit 1 else eval echo `gettext 'Stopped $APP_LONG_NAME.'` fi fi } pause() { eval echo `gettext 'Pausing $APP_LONG_NAME.'` } resume() { eval echo `gettext 'Resuming $APP_LONG_NAME.'` } status() { getpid if [ "X$pid" = "X" ] then eval echo `gettext '$APP_LONG_NAME is not running.'` exit 1 else if [ "X$DETAIL_STATUS" = "X" ] then eval echo `gettext '$APP_LONG_NAME is running: PID:$pid'` else getstatus eval echo `gettext '$APP_LONG_NAME is running: PID:$pid, Wrapper:$STATUS, Java:$JAVASTATUS'` fi exit 0 fi } # Make sure APP_NAME is less than 14 characters, otherwise in AIX, the command # "lsitab" will fail validateAppNameLength() { if [ ${#APP_NAME} -gt 14 ] ; then eval echo `gettext ' APP_NAME (${APP_NAME}) must be less than 14 characters long'` exit 1 fi } installUpstart() { eval echo `gettext ' Installing the $APP_LONG_NAME daemon using upstart..'` if [ -f "${REALDIR}/${APP_NAME}.install" ] ; then eval echo `gettext ' a custom upstart conf file ${APP_NAME}.install found'` cp "${REALDIR}/${APP_NAME}.install" "/etc/init/${APP_NAME}.conf" else eval echo `gettext ' creating default upstart conf file..'` echo "# ${APP_NAME} - ${APP_LONG_NAME}" > "/etc/init/${APP_NAME}.conf" echo "description \"${APP_LONG_NAME}\"" >> "/etc/init/${APP_NAME}.conf" echo "author \"Tanuki Software Ltd. \"" >> "/etc/init/${APP_NAME}.conf" echo "start on runlevel [2345]" >> "/etc/init/${APP_NAME}.conf" echo "stop on runlevel [!2345]" >> "/etc/init/${APP_NAME}.conf" echo "env LANG=${LANG}" >> "/etc/init/${APP_NAME}.conf" echo "exec \"${REALPATH}\" upstartinternal" >> "/etc/init/${APP_NAME}.conf" fi } installdaemon() { mustBeRootOrExit APP_NAME_LOWER=`echo "$APP_NAME" | $TR_BIN "[A-Z]" "[a-z]"` if [ "$DIST_OS" = "solaris" ] ; then eval echo `gettext 'Detected Solaris:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` ln -s "$REALPATH" "/etc/init.d/$APP_NAME" for i in `ls "/etc/rc3.d/K"??"$APP_NAME_LOWER" "/etc/rc3.d/S"??"$APP_NAME_LOWER" 2>/dev/null` ; do eval echo `gettext ' Removing unexpected file before proceeding: $i'` rm -f $i done ln -s "/etc/init.d/$APP_NAME" "/etc/rc3.d/K${APP_RUN_LEVEL_K}$APP_NAME_LOWER" ln -s "/etc/init.d/$APP_NAME" "/etc/rc3.d/S${APP_RUN_LEVEL_S}$APP_NAME_LOWER" fi elif [ "$DIST_OS" = "linux" ] ; then if [ -f /etc/redhat-release -o -f /etc/redhat_version -o -f /etc/fedora-release ] ; then eval echo `gettext 'Detected RHEL or Fedora:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" -o -f "/etc/init/${APP_NAME}.conf" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 elif [ -n "$USE_SYSTEMD" -a -d "/etc/systemd" ] ; then systemdInstall else if [ -n "$USE_UPSTART" -a -d "/etc/init" ] ; then installUpstart else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` ln -s "$REALPATH" "/etc/init.d/$APP_NAME" /sbin/chkconfig --add "$APP_NAME" /sbin/chkconfig "$APP_NAME" on fi fi elif [ -f /etc/SuSE-release ] ; then eval echo `gettext 'Detected SuSE or SLES:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 elif [ -n "$USE_SYSTEMD" -a -d "/etc/systemd" ] ; then systemdInstall else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` ln -s "$REALPATH" "/etc/init.d/$APP_NAME" insserv "/etc/init.d/$APP_NAME" fi elif [ -f /etc/lsb-release -o -f /etc/debian_version -o -f /etc/debian_release ] ; then eval echo `gettext 'Detected Ubuntu or Debian:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" -o -f "/etc/init/${APP_NAME}.conf" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 else if [ -n "$USE_SYSTEMD" -a -d "/etc/systemd" ] ; then systemdInstall elif [ -n "$USE_UPSTART" -a -d "/etc/init" ] ; then installUpstart else eval echo `gettext ' Installing the $APP_LONG_NAME daemon using init.d..'` ln -s "$REALPATH" "/etc/init.d/$APP_NAME" update-rc.d "$APP_NAME" defaults fi fi else eval echo `gettext 'Detected Linux:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` ln -s "$REALPATH" /etc/init.d/$APP_NAME for i in `ls "/etc/rc3.d/K"??"$APP_NAME_LOWER" "/etc/rc5.d/K"??"$APP_NAME_LOWER" "/etc/rc3.d/S"??"$APP_NAME_LOWER" "/etc/rc5.d/S"??"$APP_NAME_LOWER" 2>/dev/null` ; do eval echo `gettext ' Removing unexpected file before proceeding: $i'` rm -f $i done ln -s "/etc/init.d/$APP_NAME" "/etc/rc3.d/K${APP_RUN_LEVEL_K}$APP_NAME_LOWER" ln -s "/etc/init.d/$APP_NAME" "/etc/rc3.d/S${APP_RUN_LEVEL_S}$APP_NAME_LOWER" ln -s "/etc/init.d/$APP_NAME" "/etc/rc5.d/S${APP_RUN_LEVEL_S}$APP_NAME_LOWER" ln -s "/etc/init.d/$APP_NAME" "/etc/rc5.d/K${APP_RUN_LEVEL_K}$APP_NAME_LOWER" fi fi elif [ "$DIST_OS" = "hpux" ] ; then eval echo `gettext 'Detected HP-UX:'` if [ -f "/sbin/init.d/$APP_NAME" -o -L "/sbin/init.d/$APP_NAME" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` ln -s "$REALPATH" "/sbin/init.d/$APP_NAME" for i in `ls "/etc/rc3.d/K"??"$APP_NAME_LOWER" "/etc/rc3.d/S"??"$APP_NAME_LOWER" 2>/dev/null` ; do eval echo `gettext ' Removing unexpected file before proceeding: $i'` rm -f $i done ln -s "/sbin/init.d/$APP_NAME" "/sbin/rc3.d/K${APP_RUN_LEVEL_K}$APP_NAME_LOWER" ln -s "/sbin/init.d/$APP_NAME" "/sbin/rc3.d/S${APP_RUN_LEVEL_S}$APP_NAME_LOWER" fi elif [ "$DIST_OS" = "aix" ] ; then eval echo `gettext 'Detected AIX:'` validateAppNameLength if [ -f "/etc/rc.d/init.d/$APP_NAME" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed as rc.d script.'` exit 1 elif [ -n "`/usr/sbin/lsitab $APP_NAME`" -a -n "`/usr/bin/lssrc -S -s $APP_NAME`" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed as SRC service.'` exit 1 else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` if [ -n "`/usr/sbin/lsitab install_assist`" ] ; then eval echo `gettext ' The task /usr/sbin/install_assist was found in the inittab, this might cause problems for all subsequent tasks to launch at this process is known to block the init task. Please make sure this task is not needed anymore and remove/deactivate it.'` fi for i in `ls "/etc/rc.d/rc2.d/K"??"$APP_NAME_LOWER" "/etc/rc.d/rc2.d/S"??"$APP_NAME_LOWER" 2>/dev/null` ; do eval echo `gettext ' Removing unexpected file before proceeding: $i'` rm -f $i done /usr/bin/mkssys -s "$APP_NAME" -p "$REALPATH" -a "launchdinternal" -u 0 -f 9 -n 15 -S /usr/sbin/mkitab "$APP_NAME":2:once:"/usr/bin/startsrc -s \"${APP_NAME}\" >/dev/console 2>&1" fi elif [ "$DIST_OS" = "freebsd" ] ; then eval echo `gettext 'Detected FreeBSD:'` if [ -f "/etc/rc.d/$APP_NAME" -o -L "/etc/rc.d/$APP_NAME" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` sed -i .bak "/${APP_NAME}_enable=\"YES\"/d" /etc/rc.conf if [ -f "${REALDIR}/${APP_NAME}.install" ] ; then ln -s "${REALDIR}/${APP_NAME}.install" "/etc/rc.d/$APP_NAME" else echo '#!/bin/sh' > "/etc/rc.d/$APP_NAME" echo "#" >> "/etc/rc.d/$APP_NAME" echo "# PROVIDE: $APP_NAME" >> "/etc/rc.d/$APP_NAME" echo "# REQUIRE: NETWORKING" >> "/etc/rc.d/$APP_NAME" echo "# KEYWORD: shutdown" >> "/etc/rc.d/$APP_NAME" echo ". /etc/rc.subr" >> "/etc/rc.d/$APP_NAME" echo "name=\"$APP_NAME\"" >> "/etc/rc.d/$APP_NAME" echo "rcvar=\`set_rcvar\`" >> "/etc/rc.d/$APP_NAME" echo "command=\"${REALPATH}\"" >> "/etc/rc.d/$APP_NAME" echo 'start_cmd="${name}_start"' >> "/etc/rc.d/$APP_NAME" echo 'load_rc_config $name' >> "/etc/rc.d/$APP_NAME" echo 'status_cmd="${name}_status"' >> "/etc/rc.d/$APP_NAME" echo 'stop_cmd="${name}_stop"' >> "/etc/rc.d/$APP_NAME" echo "${APP_NAME}_status() {" >> "/etc/rc.d/$APP_NAME" echo '${command} status' >> "/etc/rc.d/$APP_NAME" echo '}' >> "/etc/rc.d/$APP_NAME" echo "${APP_NAME}_stop() {" >> "/etc/rc.d/$APP_NAME" echo '${command} stop' >> "/etc/rc.d/$APP_NAME" echo '}' >> "/etc/rc.d/$APP_NAME" echo "${APP_NAME}_start() {" >> "/etc/rc.d/$APP_NAME" echo '${command} start' >> "/etc/rc.d/$APP_NAME" echo '}' >> "/etc/rc.d/$APP_NAME" echo 'run_rc_command "$1"' >> "/etc/rc.d/$APP_NAME" fi echo "${APP_NAME}_enable=\"YES\"" >> /etc/rc.conf chmod 555 "/etc/rc.d/$APP_NAME" fi elif [ "$DIST_OS" = "macosx" ] ; then eval echo `gettext 'Detected Mac OSX:'` if [ -f "/Library/LaunchDaemons/${APP_PLIST}" -o -L "/Library/LaunchDaemons/${APP_PLIST}" ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` if [ -f "${REALDIR}/${APP_PLIST}" ] ; then ln -s "${REALDIR}/${APP_PLIST}" "/Library/LaunchDaemons/${APP_PLIST}" else echo "" > "/Library/LaunchDaemons/${APP_PLIST}" echo "> "/Library/LaunchDaemons/${APP_PLIST}" echo "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" >> "/Library/LaunchDaemons/${APP_PLIST}" echo "" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " " >> "/Library/LaunchDaemons/${APP_PLIST}" echo " Label" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " ${APP_PLIST_BASE}" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " ProgramArguments" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " " >> "/Library/LaunchDaemons/${APP_PLIST}" echo " ${REALPATH}" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " launchdinternal" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " " >> "/Library/LaunchDaemons/${APP_PLIST}" echo " ${KEY_KEEP_ALIVE}" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " " >> "/Library/LaunchDaemons/${APP_PLIST}" echo " RunAtLoad" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " " >> "/Library/LaunchDaemons/${APP_PLIST}" if [ "X$RUN_AS_USER" != "X" ] ; then echo " UserName" >> "/Library/LaunchDaemons/${APP_PLIST}" echo " ${RUN_AS_USER}" >> "/Library/LaunchDaemons/${APP_PLIST}" fi echo " " >> "/Library/LaunchDaemons/${APP_PLIST}" echo "" >> "/Library/LaunchDaemons/${APP_PLIST}" fi chmod 555 "/Library/LaunchDaemons/${APP_PLIST}" fi elif [ "$DIST_OS" = "zos" ] ; then eval echo `gettext 'Detected z/OS:'` if [ -f /etc/rc.bak ] ; then eval echo `gettext ' The $APP_LONG_NAME daemon is already installed.'` exit 1 else eval echo `gettext ' Installing the $APP_LONG_NAME daemon..'` cp /etc/rc /etc/rc.bak sed "s:echo /etc/rc script executed, \`date\`::g" /etc/rc.bak > /etc/rc echo "_BPX_JOBNAME='${APP_NAME}' \"${REALDIR}/${APP_NAME}\" start" >>/etc/rc echo '/etc/rc script executed, `date`' >>/etc/rc fi else eval echo `gettext 'Install not currently supported for $DIST_OS'` exit 1 fi } removedaemon() { mustBeRootOrExit APP_NAME_LOWER=`echo "$APP_NAME" | $TR_BIN "[A-Z]" "[a-z]"` if [ "$DIST_OS" = "solaris" ] ; then eval echo `gettext 'Detected Solaris:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` for i in `ls "/etc/rc3.d/K"??"$APP_NAME_LOWER" "/etc/rc3.d/S"??"$APP_NAME_LOWER" "/etc/init.d/$APP_NAME" 2>/dev/null` ; do rm -f $i done else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi elif [ "$DIST_OS" = "linux" ] ; then if [ -f /etc/redhat-release -o -f /etc/redhat_version -o -f /etc/fedora-release ] ; then eval echo `gettext 'Detected RHEL or Fedora:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` /sbin/chkconfig "$APP_NAME" off /sbin/chkconfig --del "$APP_NAME" rm -f "/etc/init.d/$APP_NAME" elif [ -n "$USE_SYSTEMD" -a -f "${SYSTEMD_SERVICE_FILE}" ] ; then systemdRemove elif [ -f "/etc/init/${APP_NAME}.conf" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon from upstart...'` rm "/etc/init/${APP_NAME}.conf" else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi elif [ -f /etc/SuSE-release ] ; then eval echo `gettext 'Detected SuSE or SLES:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` insserv -r "/etc/init.d/$APP_NAME" rm -f "/etc/init.d/$APP_NAME" elif [ -n "$USE_SYSTEMD" -a -f "${SYSTEMD_SERVICE_FILE}" ] ; then systemdRemove else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi elif [ -f /etc/lsb-release -o -f /etc/debian_version -o -f /etc/debian_release ] ; then eval echo `gettext 'Detected Ubuntu or Debian:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon from init.d...'` update-rc.d -f "$APP_NAME" remove rm -f "/etc/init.d/$APP_NAME" elif [ -n "$USE_SYSTEMD" -a -f "${SYSTEMD_SERVICE_FILE}" ] ; then systemdRemove elif [ -f "/etc/init/${APP_NAME}.conf" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon from upstart...'` rm "/etc/init/${APP_NAME}.conf" else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi else eval echo `gettext 'Detected Linux:'` if [ -f "/etc/init.d/$APP_NAME" -o -L "/etc/init.d/$APP_NAME" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` for i in `ls "/etc/rc3.d/K"??"$APP_NAME_LOWER" "/etc/rc5.d/K"??"$APP_NAME_LOWER" "/etc/rc3.d/S"??"$APP_NAME_LOWER" "/etc/rc5.d/S"??"$APP_NAME_LOWER" "/etc/init.d/$APP_NAME" 2>/dev/null` ; do rm -f $i done else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi fi elif [ "$DIST_OS" = "hpux" ] ; then eval echo `gettext 'Detected HP-UX:'` if [ -f "/sbin/init.d/$APP_NAME" -o -L "/sbin/init.d/$APP_NAME" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` for i in `ls "/etc/rc3.d/K"??"$APP_NAME_LOWER" "/etc/rc3.d/S"??"$APP_NAME_LOWER" "/etc/init.d/$APP_NAME" 2>/dev/null` ; do rm -f $i done else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi elif [ "$DIST_OS" = "aix" ] ; then eval echo `gettext 'Detected AIX:'` validateAppNameLength if [ -f "/etc/rc.d/init.d/$APP_NAME" -o -L "/etc/rc.d/init.d/$APP_NAME" -o -n "`/usr/sbin/lsitab $APP_NAME`" -o -n "`/usr/bin/lssrc -S -s $APP_NAME`" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` if [ -f "/etc/rc.d/init.d/$APP_NAME" -o -L "/etc/rc.d/init.d/$APP_NAME" ] ; then for i in `ls "/etc/rc.d/rc2.d/K"??"$APP_NAME_LOWER" "/etc/rc.d/rc2.d/S"??"$APP_NAME_LOWER" "/etc/rc.d/init.d/$APP_NAME" 2>/dev/null` ; do rm -f $i done fi if [ -n "`/usr/sbin/lsitab $APP_NAME`" -o -n "`/usr/bin/lssrc -S -s $APP_NAME`" ] ; then /usr/sbin/rmitab $APP_NAME /usr/bin/rmssys -s $APP_NAME fi else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi elif [ "$DIST_OS" = "freebsd" ] ; then eval echo `gettext 'Detected FreeBSD:'` if [ -f "/etc/rc.d/$APP_NAME" -o -L "/etc/rc.d/$APP_NAME" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` for i in "/etc/rc.d/$APP_NAME" do rm -f $i done sed -i .bak "/${APP_NAME}_enable=\"YES\"/d" /etc/rc.conf else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi elif [ "$DIST_OS" = "macosx" ] ; then eval echo `gettext 'Detected Mac OSX:'` if [ -f "/Library/LaunchDaemons/${APP_PLIST}" -o -L "/Library/LaunchDaemons/${APP_PLIST}" ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` # Make sure the plist is installed LOADED_PLIST=`launchctl list | grep ${APP_PLIST_BASE}` if [ "X${LOADED_PLIST}" != "X" ] ; then launchctl unload "/Library/LaunchDaemons/${APP_PLIST}" fi rm -f "/Library/LaunchDaemons/${APP_PLIST}" else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi elif [ "$DIST_OS" = "zos" ] ; then eval echo `gettext 'Detected z/OS:'` if [ -f /etc/rc.bak ] ; then stopit "0" eval echo `gettext ' Removing $APP_LONG_NAME daemon...'` cp /etc/rc /etc/rc.bak sed "s/_BPX_JOBNAME=\'APP_NAME\'.*//g" /etc/rc.bak > /etc/rc rm /etc/rc.bak else eval echo `gettext ' The $APP_LONG_NAME daemon is not currently installed.'` exit 1 fi else eval echo `gettext 'Remove not currently supported for $DIST_OS'` exit 1 fi } dump() { eval echo `gettext 'Dumping $APP_LONG_NAME...'` getpid if [ "X$pid" = "X" ] then eval echo `gettext '$APP_LONG_NAME was not running.'` else kill -3 $pid if [ $? -ne 0 ] then eval echo `gettext 'Failed to dump $APP_LONG_NAME.'` exit 1 else eval echo `gettext 'Dumped $APP_LONG_NAME.'` fi fi } # Used by HP-UX init scripts. startmsg() { getpid if [ "X$pid" = "X" ] then eval echo `gettext 'Starting $APP_LONG_NAME... Wrapper:Stopped'` else if [ "X$DETAIL_STATUS" = "X" ] then eval echo `gettext 'Starting $APP_LONG_NAME... Wrapper:Running'` else getstatus eval echo `gettext 'Starting $APP_LONG_NAME... Wrapper:$STATUS, Java:$JAVASTATUS'` fi fi } # Used by HP-UX init scripts. stopmsg() { getpid if [ "X$pid" = "X" ] then eval echo `gettext 'Stopping $APP_LONG_NAME... Wrapper:Stopped'` else if [ "X$DETAIL_STATUS" = "X" ] then eval echo `gettext 'Stopping $APP_LONG_NAME... Wrapper:Running'` else getstatus eval echo `gettext 'Stopping $APP_LONG_NAME... Wrapper:$STATUS, Java:$JAVASTATUS'` fi fi } showUsage() { # $1 bad command if [ -n "$1" ] then eval echo `gettext 'Unexpected command: $1'` echo ""; fi eval MSG=`gettext 'Usage: '` if [ -n "$FIXED_COMMAND" ] ; then if [ -n "$PASS_THROUGH" ] ; then echo "${MSG} $0 {JavaAppArgs}" else echo "${MSG} $0" fi else if [ -n "$PAUSABLE" ] ; then if [ -n "$PASS_THROUGH" ] ; then echo "${MSG} $0 [ console {JavaAppArgs} | start {JavaAppArgs} | stop | restart {JavaAppArgs} | condrestart {JavaAppArgs} | pause | resume | status | install | remove | dump ]" else echo "${MSG} $0 [ console | start | stop | restart | condrestart | pause | resume | status | install | remove | dump ]" fi else if [ -n "$PASS_THROUGH" ] ; then echo "${MSG} $0 [ console {JavaAppArgs} | start {JavaAppArgs} | stop | restart {JavaAppArgs} | condrestart {JavaAppArgs} | status | install | remove | dump ]" else echo "${MSG} $0 [ console | start | stop | restart | condrestart | status | install | remove | dump ]" fi fi fi if [ ! -n "$BRIEF_USAGE" ] then echo ""; if [ ! -n "$FIXED_COMMAND" ] ; then echo "`gettext 'Commands:'`" echo "`gettext ' console Launch in the current console.'`" echo "`gettext ' start Start in the background as a daemon process.'`" echo "`gettext ' stop Stop if running as a daemon or in another console.'`" echo "`gettext ' restart Stop if running and then start.'`" echo "`gettext ' condrestart Restart only if already running.'`" if [ -n "$PAUSABLE" ] ; then echo "`gettext ' pause Pause if running.'`" echo "`gettext ' resume Resume if paused.'`" fi echo "`gettext ' status Query the current status.'`" echo "`gettext ' install Install to start automatically when system boots.'`" echo "`gettext ' remove Uninstall.'`" echo "`gettext ' dump Request a Java thread dump if running.'`" echo ""; fi if [ -n "$PASS_THROUGH" ] ; then echo "`gettext 'JavaAppArgs: Zero or more arguments which will be passed to the Java application.'`" echo ""; fi fi exit 1 } docommand() { case "$COMMAND" in 'console') checkUser touchlock "$@" if [ ! -n "$FIXED_COMMAND" ] ; then shift fi console "$@" ;; 'start') if [ "$DIST_OS" = "macosx" -a -f "/Library/LaunchDaemons/${APP_PLIST}" ] ; then macosxStart elif [ "$DIST_OS" = "linux" -a -f "/etc/init/${APP_NAME}.conf" ] ; then upstartstart elif [ "$DIST_OS" = "linux" -a -n "$USE_SYSTEMD" -a -z "$SYSD" ] ; then systemdStart else if [ -n "$SYSD" ] ; then shift fi checkUser touchlock "$@" if [ ! -n "$FIXED_COMMAND" ] ; then shift fi start "$@" fi ;; 'stop') if [ "$DIST_OS" = "macosx" -a -f "/Library/LaunchDaemons/${APP_PLIST}" ] ; then macosxStop elif [ "$DIST_OS" = "linux" -a -f "/etc/init/${APP_NAME}.conf" ] ; then upstartStop elif [ "$DIST_OS" = "linux" -a -n "$USE_SYSTEMD" -a -z "$SYSD" ] ; then systemdStop else checkUser "" "$COMMAND" stopit "0" fi ;; 'restart') if [ "$DIST_OS" = "macosx" -a -f "/Library/LaunchDaemons/${APP_PLIST}" ] ; then macosxRestart elif [ "$DIST_OS" = "linux" -a -f "/etc/init/${APP_NAME}.conf" ] ; then upstartRestart elif [ "$DIST_OS" = "linux" -a -n "$USE_SYSTEMD" -a -z "$SYSD" ] ; then systemdRestart else if [ -n "$SMF" ] ; then shift fi checkUser touchlock "$COMMAND" if [ ! -n "$FIXED_COMMAND" ] ; then shift fi stopit "0" start "$@" fi ;; 'condrestart') checkUser touchlock "$COMMAND" if [ ! -n "$FIXED_COMMAND" ] ; then shift fi stopit "1" start "$@" ;; 'pause') if [ -n "$PAUSABLE" ] then pause else showUsage "$COMMAND" fi ;; 'resume') if [ -n "$PAUSABLE" ] then resume else showUsage "$COMMAND" fi ;; 'status') status ;; 'install') installdaemon ;; 'remove') removedaemon ;; 'dump') checkUser "" "$COMMAND" dump ;; 'start_msg') # Internal command called by launchd on HP-UX. checkUser "" "$COMMAND" startmsg ;; 'stop_msg') # Internal command called by launchd on HP-UX. checkUser "" "$COMMAND" stopmsg ;; 'launchdinternal' | 'upstartinternal') if [ ! "$DIST_OS" = "macosx" -o ! -f "/Library/LaunchDaemons/${APP_PLIST}" ] ; then checkUser touchlock "$@" fi # Internal command called by launchd on Max OSX. # We do not want to call checkUser here as it is handled in the launchd plist file. Doing it here would confuse launchd. if [ ! -n "$FIXED_COMMAND" ] ; then shift fi launchinternal "$@" ;; *) showUsage "$COMMAND" ;; esac } docommand "$@" exit 0 wrapper_3.5.26_src/src/c/MSG00001.bin100644 0 0 300 12440202300 14015 0ustar 0 0  dd jvm1 jvm2 jvm3 jvm4 jvm5 jvm6 jvm7 jvm8 jvm9 jvmxx wrapper wrapperp %2 wrapper_3.5.26_src/src/c/Makefile-aix-ppc-32.gmake100644 0 0 2214 12440202300 16646 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -DAIX -D_THREAD_SAFE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/aix wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_a_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.a clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.a init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lpthread -lnsl -lm $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.a: $(libwrapper_a_OBJECTS) ${COMPILE} -shared $(libwrapper_a_OBJECTS) -o $(LIB)/libwrapper.a %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-aix-ppc-32.make100644 0 0 2712 12440202300 16502 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -fPIC --pedantic -DAIX -D_FILE_OFFSET_BITS=64 -liconv -DUNICODE -D_UNICODE -D_THREAD_SAFE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/aix wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_a_SOURCE = wrapper_i18n.c wrapperjni_unix.c wrapperinfo.c wrapperjni.c loggerjni.c BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.a clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.a init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lpthread -lnsl -lm $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.a: $(libwrapper_a_SOURCE) ${COMPILE} $(DEFS) -shared -lpthread $(libwrapper_a_SOURCE) -o $(LIB)/libwrapper.a %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-aix-ppc-64.gmake100644 0 0 2210 12440202300 16647 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -DAIX -DJSW64 -maix64 -DUNICODE -D_UNICODE -D_THREAD_SAFE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/aix wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_a_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.a clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.a init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lpthread -lnsl -lm $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.a: $(libwrapper_a_OBJECTS) ${COMPILE} -shared $(libwrapper_a_OBJECTS) -o $(LIB)/libwrapper.a %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-aix-ppc-64.make100644 0 0 2732 12440202300 16511 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -fPIC --pedantic -DAIX -DJSW64 -maix64 -D_FILE_OFFSET_BITS=64 -liconv -DUNICODE -D_UNICODE -D_THREAD_SAFE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/aix wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_a_SOURCE = wrapper_i18n.c wrapperjni_unix.c wrapperinfo.c wrapperjni.c loggerjni.c BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.a clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.a init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lpthread -lnsl -lm $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.a: $(libwrapper_a_SOURCE) ${COMPILE} $(DEFS) -shared -lpthread $(libwrapper_a_SOURCE) -o $(LIB)/libwrapper.a %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-freebsd-x86-32.gmake100644 0 0 2354 12440202300 17347 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html CC = gcc -Wall -pedantic -DFREEBSD -I/usr/local/include -L/usr/local/lib -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include CFLAGS = -I$(INCLUDE) -I$(INCLUDE)/freebsd wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(CC) $(wrapper_SOURCE) -lm -lcompat -rdynamic -lc -pthread -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) $(CC) -shared -rdynamic -lc $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so #%.o: %.c # $(COMPILE) -c $(DEFS) $< wrapper_3.5.26_src/src/c/Makefile-freebsd-x86-64.gmake100644 0 0 2372 12440202300 17354 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html CC = gcc -Wall -pedantic -DFREEBSD -DJSW64 -fPIC -I/usr/local/include -L/usr/local/lib -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include CFLAGS = -I$(INCLUDE) -I$(INCLUDE)/freebsd wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(CC) $(wrapper_SOURCE) -lm -lcompat -rdynamic -lc -pthread -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) $(CC) -shared -rdynamic -lc $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so #%.o: %.c # $(COMPILE) -c $(DEFS) $< wrapper_3.5.26_src/src/c/Makefile-hpux-ia-32.gmake100644 0 0 2314 12440202300 16661 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -Wall --pedantic -DHPUX -D_INCLUDE__STDC_A1_SOURCE -DARCH_IA -D_XOPEN_SOURCE_EXTENDED -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/hp-ux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) $(wrapper_SOURCE) -lm -lpthread -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -fPIC -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -fPIC -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-hpux-ia-32.make100644 0 0 2311 12440202300 16507 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = cc -DHPUX -Ae +Z -D_INCLUDE__STDC_A1_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/hp-ux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_SOURCE = wrapper_i18n.c wrapperjni_unix.c wrapperinfo.c wrapperjni.c loggerjni.c BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) $(wrapper_SOURCE) -lm -lpthread -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_SOURCE) ${COMPILE} ${DEFS} $(libwrapper_so_SOURCE) -b -lm -lpthread -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-hpux-ia-64.gmake100644 0 0 2301 12440202300 16662 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -Wall -mlp64 --pedantic -DHPUX -DJSW64 -DARCH_IA -D_XOPEN_SOURCE_EXTENDED -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/hp-ux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) $(wrapper_SOURCE) -lm -lpthread -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -fPIC -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -fPIC -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-hpux-ia-64.make100644 0 0 2326 12440202300 16522 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = cc +z +DD64 -O3 -DHPUX -DJSW64 -D_INCLUDE__STDC_A1_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/hp-ux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_SOURCE = wrapper_i18n.c wrapperjni_unix.c wrapperinfo.c wrapperjni.c loggerjni.c BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) $(wrapper_SOURCE) -lm -lpthread -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_SOURCE) ${COMPILE} ${DEFS} $(libwrapper_so_SOURCE) -b -lm -lpthread -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-hpux-parisc-32.gmake100644 0 0 2302 12440202300 17546 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -Wall -D_INCLUDE__STDC_A1_SOURCE --pedantic -DHPUX -D_XOPEN_SOURCE_EXTENDED -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/hp-ux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_sl_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.sl clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.sl init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) $(wrapper_SOURCE) -lm -lpthread -o $(BIN)/wrapper libwrapper.sl: $(libwrapper_sl_OBJECTS) ${COMPILE} -fPIC -shared $(libwrapper_sl_OBJECTS) -o $(LIB)/libwrapper.sl %.o: %.c ${COMPILE} -fPIC -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-hpux-parisc-32.make100644 0 0 2332 12440202300 17402 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = cc -DHPUX -Ae -D_INCLUDE__STDC_A1_SOURCE +Z +DAportable +DS1.1 -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/hp-ux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_sl_SOURCE = wrapper_i18n.c wrapperjni_unix.c wrapperinfo.c wrapperjni.c loggerjni.c BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.sl clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.sl init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) $(wrapper_SOURCE) -lm -lpthread -o $(BIN)/wrapper libwrapper.sl: $(libwrapper_sl_SOURCE) ${COMPILE} ${DEFS} $(libwrapper_sl_SOURCE) -b -lm -lpthread -o $(LIB)/libwrapper.sl %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-hpux-parisc-64.make100644 0 0 2333 12440202300 17410 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = cc +z +DD64 -D_INCLUDE__STDC_A1_SOURCE -O3 -Wall -DHPUX -DJSW64 -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/hp-ux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_sl_SOURCE = wrapper_i18n.c wrapperjni_unix.c wrapperinfo.c wrapperjni.c loggerjni.c BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.sl clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.sl init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) $(wrapper_SOURCE) -lm -lpthread -o $(BIN)/wrapper libwrapper.sl: $(libwrapper_sl_SOURCE) ${COMPILE} ${DEFS} $(libwrapper_sl_SOURCE) -b -lm -lpthread -o $(LIB)/libwrapper.sl %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-irix-mips-32.cc100644 0 0 2515 12440202300 16533 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html # Makefile for SGI IRIX 6.5 (may work on other versions as well but not tested) # MIPSpro Compilers: Version 7.3.1.3m COMPILE = cc -DIRIX -KPIC -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/irix wrapper_OBJECTS = wrapper.o wrapperinfo.o wrappereventloop.o wrapper_unix.o property.o logger.o logger_file.o wrapper_file.o wrapper_i18n.o wrapper_hashmap.o libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_OBJECTS) $(COMPILE) $(wrapper_OBJECTS) -o $(BIN)/wrapper -lm -lpthread libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared -no_unresolved -n32 -all $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -c $< wrapper_3.5.26_src/src/c/Makefile-irix-mips-32.gmake100644 0 0 2642 12440202300 17233 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -DIRIX -D_GNU_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/irix -DUNICODE -D_UNICODE wrapper_OBJECTS = wrapper.o wrapperinfo.o wrappereventloop.o wrapper_unix.o property.o logger.o logger_file.o wrapper_file.o wrapper_i18n.o wrapper_hashmap.o libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_OBJECTS) $(COMPILE) $(wrapper_OBJECTS) -o $(BIN)/wrapper -lm -lpthread libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-linux-armel-32.make100644 0 0 2703 12440202300 17376 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -fPIC -Wall --pedantic -DLINUX -D_FILE_OFFSET_BITS=64 -fpic -D_GNU_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/linux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -pthread $(wrapper_SOURCE) -lm -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-linux-armhf-32.make100644 0 0 2703 12440202300 17373 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -fPIC -Wall --pedantic -DLINUX -D_FILE_OFFSET_BITS=64 -fpic -D_GNU_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/linux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -pthread $(wrapper_SOURCE) -lm -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-linux-ia-64.make100644 0 0 2716 12440202300 16700 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -fPIC -Wall --pedantic -DLINUX -DJSW64 -D_FILE_OFFSET_BITS=64 -fpic -D_GNU_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/linux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lm -pthread $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -lm -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-linux-ppc-32.make100644 0 0 2707 12440202300 17064 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -m32 -fPIC -Wall --pedantic -DLINUX -D_FILE_OFFSET_BITS=64 -fpic -D_GNU_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/linux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lm -pthread $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-linux-ppc-64.make100644 0 0 2717 12440202300 17072 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -m64 -fPIC -Wall --pedantic -DLINUX -DJSW64 -D_FILE_OFFSET_BITS=64 -fpic -D_GNU_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/linux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lm -pthread $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-linux-x86-32.make100644 0 0 3525 12440202300 16726 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -fPIC -Wall --pedantic -DLINUX -D_FILE_OFFSET_BITS=64 -fpic -D_GNU_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/linux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o testsuite_SOURCE = testsuite.c test_example.c test_javaadditionalparam.c test_hashmap.c test_filter.c wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c BIN = ../../bin LIB = ../../lib TEST = ../../test all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -pthread $(wrapper_SOURCE) -lm -o $(BIN)/wrapper testsuite: $(testsuite_SOURCE) $(COMPILE) -DCUNIT $(testsuite_SOURCE) -lm -pthread -L/usr/local/lib -lncurses -lcunit -o $(TEST)/testsuite libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-linux-x86-64.make100644 0 0 3547 12440202300 16737 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -fPIC -Wall --pedantic -DLINUX -DJSW64 -D_FILE_OFFSET_BITS=64 -fpic -D_GNU_SOURCE -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/linux wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o testsuite_SOURCE = testsuite.c test_example.c test_javaadditionalparam.c test_hashmap.c test_filter.c wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c BIN = ../../bin LIB = ../../lib TEST = ../../test all: init wrapper libwrapper.so testsuite clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -pthread $(wrapper_SOURCE) -lm -o $(BIN)/wrapper testsuite: $(testsuite_SOURCE) $(COMPILE) -DCUNIT $(testsuite_SOURCE) -lm -pthread -L/usr/local/lib -lncurses -lcunit -o $(TEST)/testsuite libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-macosx-universal-32.make100644 0 0 4271 12440202300 20443 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html UNIVERSAL_SDK_HOME=/Developer/SDKs/MacOSX10.5.sdk INCLUDE = -I/opt/local/include COMPILE = gcc -O3 -Wall -DUSE_NANOSLEEP -DMACOSX -arch ppc -arch i386 -isysroot $(UNIVERSAL_SDK_HOME) $(INCLUDE) -mmacosx-version-min=10.4 -DUNICODE -D_UNICODE COMPILET = gcc -O3 -Wall -DUSE_NANOSLEEP -DMACOSX -isysroot $(UNIVERSAL_SDK_HOME) $(INCLUDE) -mmacosx-version-min=10.4 -DUNICODE -D_UNICODE #COMPILE = gcc -ggdb -O1 -Wall -DUSE_NANOSLEEP -DMACOSX -DVALGRIND -isysroot $(UNIVERSAL_SDK_HOME) $(INCLUDE) -mmacosx-version-min=10.4 -DUNICODE -D_UNICODE # To debug: # 1) Add "-ggdb" # 2) Remove "-arch ppc -arch i386" # 3) Change "-O3" to "-O1" DEFS = -I$(UNIVERSAL_SDK_HOME)/System/Library/Frameworks/JavaVM.framework/Headers wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o testsuite_SOURCE = testsuite.c test_example.c test_javaadditionalparam.c test_hashmap.c test_filter.c wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c BIN = ../../bin LIB = ../../lib TEST = ../../test #all: init testsuite wrapper libwrapper.jnilib all: init wrapper libwrapper.jnilib clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.jnilib init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -DMACOSX $(wrapper_SOURCE) -liconv -o $(BIN)/wrapper libwrapper.jnilib: $(libwrapper_so_OBJECTS) $(COMPILE) -bundle -liconv -o $(LIB)/libwrapper.jnilib $(libwrapper_so_OBJECTS) testsuite: $(testsuite_SOURCE) $(COMPILET) -DCUNIT $(testsuite_SOURCE) -liconv -lncurses -lcunit -o $(TEST)/testsuite %.o: %.c $(COMPILE) -c $(DEFS) $< wrapper_3.5.26_src/src/c/Makefile-macosx-universal-64.make100644 0 0 2557 12440202300 20455 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html UNIVERSAL_SDK_HOME=/Developer/SDKs/MacOSX10.5.sdk COMPILE = gcc -O3 -m64 -Wall -DUSE_NANOSLEEP -DMACOSX -DJSW64 -arch ppc64 -arch x86_64 -isysroot $(UNIVERSAL_SDK_HOME) -mmacosx-version-min=10.4 -DUNICODE -D_UNICODE DEFS = -I$(UNIVERSAL_SDK_HOME)/System/Library/Frameworks/JavaVM.framework/Headers wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.jnilib clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.jnilib init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -DMACOSX $(wrapper_SOURCE) -liconv -o $(BIN)/wrapper libwrapper.jnilib: $(libwrapper_so_OBJECTS) $(COMPILE) -bundle -liconv -o $(LIB)/libwrapper.jnilib $(libwrapper_so_OBJECTS) %.o: %.c $(COMPILE) -c $(DEFS) $< wrapper_3.5.26_src/src/c/Makefile-osf1-alpha-64.gmake100644 0 0 2270 12440202300 17247 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -DOSF1 -DJSW64 -D_REENTRANT -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/alpha wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lpthread -lm -ldb -lrt $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -shared $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-solaris-sparc-32.gmake100644 0 0 2373 12440202300 20075 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = /opt/studio12/SUNWspro/bin/cc -mt -Kpic -O -DSOLARIS -DJSW64 -D_REENTRANT -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/solaris wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lsocket -lpthread -lnsl -lm -lposix4 $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-solaris-sparc-32.make100644 0 0 2615 12440202300 17725 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -Wall --pedantic -DSOLARIS -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/solaris wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lsocket -lpthread -lnsl -lm -lposix4 $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-solaris-sparc-64.gmake100644 0 0 2400 12440202300 20071 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = /opt/studio12/SUNWspro/bin/cc -m64 -mt -Kpic -O -DSOLARIS -DJSW64 -D_REENTRANT -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/solaris wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lsocket -lpthread -lnsl -lm -lposix4 $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-solaris-sparc-64.make100644 0 0 2632 12440202300 17731 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -m64 -O3 -Wall --pedantic -DJSW64 -DSOLARIS -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/solaris wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lsocket -lpthread -lnsl -lm -lposix4 $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-solaris-x86-32.gmake100644 0 0 2453 12440202300 17411 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html # gcc -O3 -Wall --pedantic -DSOLARIS -liconv -DUNICODE -D_UNICODE COMPILE = /opt/SUNWspro/bin/cc -mt -Kpic -O -DSOLARIS -DUNICODE -D_UNICODE -D_REENTRANT INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/solaris wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lsocket -lpthread -lnsl -lm -lposix4 $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-solaris-x86-32.make100644 0 0 2614 12440202300 17241 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -O3 -Wall --pedantic -DSOLARIS -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/solaris wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lsocket -lpthread -lnsl -lm -lposix4 $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-solaris-x86-64.gmake100644 0 0 3307 12440202300 17415 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html # gcc - The JNI library generated with gcc does not work on 64-bit x86 systems # due to a bug or simply a configuration problem. We need to use cc here. # see Bug #1992039 for details. # https://sourceforge.net/tracker/index.php?func=detail&aid=1992039&group_id=39428&atid=425187 #COMPILE = gcc -m64 -O3 -Wall --pedantic -DSOLARIS -DJSW64 COMPILE = /opt/SUNWspro/bin/cc -m64 -mt -Kpic -O -DSOLARIS -DJSW64 -DUNICODE -D_UNICODE -D_REENTRANT INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/solaris wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c logger_file.c wrapper_file.c wrapper_i18n.c wrapper_hashmap.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o loggerjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lsocket -lpthread -lnsl -lm -lposix4 $(wrapper_SOURCE) -o $(BIN)/wrapper #libwrapper.so: $(libwrapper_so_OBJECTS) # ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c ${COMPILE} -c ${DEFS} $< wrapper_3.5.26_src/src/c/Makefile-solaris-x86-64.make100644 0 0 2631 12440202300 17245 0ustar 0 0 # Copyright (c) 1999, 2012 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html COMPILE = gcc -m64 -O3 -Wall --pedantic -DSOLARIS -DJSW64 -DUNICODE -D_UNICODE INCLUDE=$(JAVA_HOME)/include DEFS = -I$(INCLUDE) -I$(INCLUDE)/solaris wrapper_SOURCE = wrapper.c wrapperinfo.c wrappereventloop.c wrapper_unix.c property.c logger.c wrapper_file.c wrapper_i18n.c libwrapper_so_OBJECTS = wrapper_i18n.o wrapperjni_unix.o wrapperinfo.o wrapperjni.o BIN = ../../bin LIB = ../../lib all: init wrapper libwrapper.so clean: rm -f *.o cleanall: clean rm -rf *~ .deps rm -f $(BIN)/wrapper $(LIB)/libwrapper.so init: if test ! -d .deps; then mkdir .deps; fi wrapper: $(wrapper_SOURCE) $(COMPILE) -lsocket -lpthread -lnsl -lm -lposix4 $(wrapper_SOURCE) -o $(BIN)/wrapper libwrapper.so: $(libwrapper_so_OBJECTS) ${COMPILE} -G -fPIC -lposix4 $(libwrapper_so_OBJECTS) -o $(LIB)/libwrapper.so %.o: %.c @echo '$(COMPILE) -c $<'; \ $(COMPILE) $(DEFS) -Wp,-MD,.deps/$(*F).pp -c $< @-cp .deps/$(*F).pp .deps/$(*F).P; \ tr ' ' '\012' < .deps/$(*F).pp \ | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*F).P; \ rm .deps/$(*F).pp wrapper_3.5.26_src/src/c/Makefile-windows-x86-32.nmake100644 0 0 6413 12440202300 17436 0ustar 0 0 # Copyright (c) 1999, 2014 Tanuki Software, Ltd. # http://www.tanukisoftware.com # All rights reserved. # # This software is the proprietary information of Tanuki Software. # You shall use it only in accordance with the terms of the # license agreement you entered into with Tanuki Software. # http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html PROJ = wrapper COMPILE = cl /D "WIN32" /D "NDEBUG" /FD /EHsc /MT /W3 /nologo /c /Zi /errorReport:prompt /D "_CRT_SECURE_NO_DEPRECATE" /D "UNICODE" /D "_UNICODE" /D "_WIN32_WINNT=0x0500" LINK = link /NOLOGO /MANIFEST /DEBUG /MACHINE:X86 /ERRORREPORT:PROMPT DelayImp.lib RC = rc # EXE Definitions EXE_OUTDIR = $(PROJ)32_VC8__Win32_Release EXE_OBJS = $(EXE_OUTDIR)\wrapper.obj $(EXE_OUTDIR)\wrapperinfo.obj $(EXE_OUTDIR)\wrappereventloop.obj $(EXE_OUTDIR)\wrapper_win.obj $(EXE_OUTDIR)\property.obj $(EXE_OUTDIR)\logger.obj $(EXE_OUTDIR)\logger_file.obj $(EXE_OUTDIR)\wrapper_file.obj $(EXE_OUTDIR)\wrapper_i18n.obj $(EXE_OUTDIR)\wrapper_hashmap.obj EXE_LIBS = mpr.lib shell32.lib netapi32.lib wsock32.lib shlwapi.lib advapi32.lib user32.lib Crypt32.lib Wintrust.lib pdh.lib EXE_COMPILE_OPTS = /O2 /GL /D "_CONSOLE" EXE_LINK_OPTS = /INCREMENTAL:NO /SUBSYSTEM:CONSOLE /MANIFESTFILE:"$(EXE_OUTDIR)\$(PROJ).exe.intermediate.manifest" /PDB:"$(EXE_OUTDIR)\$(PROJ).pdb" /OPT:REF /OPT:ICF /LTCG # DLL Definitions DLL_OUTDIR = $(PROJ)JNI32_VC8__Win32_Release DLL_OBJS = $(DLL_OUTDIR)\wrapper_i18n.obj $(DLL_OUTDIR)\wrapperjni_win.obj $(DLL_OUTDIR)\wrapperinfo.obj $(DLL_OUTDIR)\wrapperjni.obj $(DLL_OUTDIR)\loggerjni.obj DLL_LIBS = shell32.lib wsock32.lib advapi32.lib user32.lib DLL_COMPILE_OPTS = /Od /I "..\" /I ".\" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "_WINDOWS" /D "_USRDLL" /D "DECODERJNI_VC8_EXPORTS" /D "_WINDLL" DLL_LINK_OPTS = /INCREMENTAL /DLL /SUBSYSTEM:WINDOWS /MANIFESTFILE:"$(DLL_OUTDIR)\$(PROJ).dll.intermediate.manifest" /PDB:"$(DLL_OUTDIR)\$(PROJ).pdb" all: $(EXE_OUTDIR) $(DLL_OUTDIR) $(PROJ).exe $(PROJ).dll # Define project specific macros #----- If OUTDIR does not exist, then create directory $(EXE_OUTDIR) : if not exist "$(EXE_OUTDIR)/$(NULL)" mkdir $(EXE_OUTDIR) $(DLL_OUTDIR) : if not exist "$(DLL_OUTDIR)/$(NULL)" mkdir $(DLL_OUTDIR) # Inference rule for updating the object files .c{$(EXE_OUTDIR)}.obj: $(COMPILE) $(EXE_COMPILE_OPTS) /Fo"$(EXE_OUTDIR)\\" /Fd"$(EXE_OUTDIR)\\" $** .c{$(DLL_OUTDIR)}.obj: $(COMPILE) $(DLL_COMPILE_OPTS) /Fo"$(DLL_OUTDIR)\\" /Fd"$(DLL_OUTDIR)\\" $** # Build rule for resource file $(EXE_OUTDIR)\$(PROJ).res: $(PROJ).rc $(RC_DEP) $(RC) /fo"$(EXE_OUTDIR)/$(PROJ).res" $(PROJ).rc $(DLL_OUTDIR)\$(PROJ).res: $(PROJ).rc $(RC_DEP) $(RC) /fo"$(DLL_OUTDIR)/$(PROJ).res" $(PROJ).rc $(PROJ).exe: $(BASE_OBJS) $(EXE_OBJS) $(EXE_OUTDIR)\$(PROJ).res $(LINK) $(EXE_LINK_OPTS) $(EXE_OBJS) $(EXE_LIBS) $(EXE_OUTDIR)\$(PROJ).res /OUT:"..\..\bin\$(PROJ).exe" $(PROJ).dll: $(BASE_OBJS) $(DLL_OBJS) $(DLL_OUTDIR)\$(PROJ).res $(LINK) $(DLL_LINK_OPTS) $(DLL_OBJS) $(DLL_LIBS) $(DLL_OUTDIR)\$(PROJ).res /OUT:"..\..\lib\$(PROJ).dll" clean: if exist $(EXE_OUTDIR)/$(NULL) rd /s /q $(EXE_OUTDIR) if exist $(DLL_OUTDIR)/$(NULL) rd /s /q $(DLL_OUTDIR) if exist ..\..\bin\$(PROJ).exe del /q ..\..\bin\$(PROJ).exe if exist ..\..\lib\$(PROJ).dll del /q ..\..\lib\$(PROJ).dll wrapper_3.5.26_src/src/c/Wrapper.rc100644 0 0 7557 12440202300 14327 0ustar 0 0 //Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // { resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) #ifdef _WIN32 LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT #pragma code_page(932) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include \r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Version // // http://msdn.microsoft.com/en-us/library/aa381058%28VS.85%29.aspx VS_VERSION_INFO VERSIONINFO FILEVERSION 3,5,26,0 PRODUCTVERSION 3,5,26,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "000904b0" BEGIN VALUE "CompanyName", "Tanuki Software, Ltd." VALUE "FileDescription", "Java Service Wrapper Community Edition 3.5.26" VALUE "FileVersion", "3, 5, 26, 0" VALUE "LegalCopyright", "Copyright (C) 1999, 2014 Tanuki Software, Ltd. All rights reserved." VALUE "InternalName", "wrapper" VALUE "OriginalFilename", "wrapper.exe" VALUE "ProductName", "Java Service Wrapper Community" VALUE "ProductVersion", "3, 5, 26, 0" END END BLOCK "VarFileInfo" BEGIN /* The following line should only be modified for localized versions. */ /* It consists of any number of WORD,WORD pairs, with each pair */ /* describing a language,codepage combination supported by the file. */ /* */ /* For example, a file might have values "0x409,1252" indicating that it */ /* supports English language (0x409) in the Windows ANSI codepage (1252). */ VALUE "Translation", 0x9, 1200 //VALUE "Translation", 0x409, 1252 //VALUE "Translation", 0x411, 932 END END #endif // { resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // p (ض) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_WRAPPER ICON DISCARDABLE "wrapper.ico" ///////////////////////////////////////////////////////////////////////////// // // Messages // 1 11 DISCARDABLE "MSG00001.bin" #endif // p (ض) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED wrapper_3.5.26_src/src/c/Wrapper32.dep.in100644 0 0 1415 12440202300 15230 0ustar 0 0 # Microsoft Developer Studio Generated Dependency File, included by Wrapper32.mak .\logger.c : \ ".\logger.h"\ ".\messages.h"\ "@msvc.home@\vc98\include\basetsd.h"\ .\property.c : \ ".\logger.h"\ ".\property.h"\ "@msvc.home@\vc98\include\basetsd.h"\ .\wrapper.c : \ ".\logger.h"\ ".\property.h"\ ".\wrapper.h"\ ".\wrapperinfo.h"\ "@msvc.home@\vc98\include\basetsd.h"\ .\wrapper_win.c : \ ".\logger.h"\ ".\property.h"\ ".\psapi.h"\ ".\wrapper.h"\ ".\wrapperinfo.h"\ "@msvc.home@\vc98\include\basetsd.h"\ .\wrappereventloop.c : \ ".\logger.h"\ ".\property.h"\ ".\wrapper.h"\ "@msvc.home@\vc98\include\basetsd.h"\ .\wrapperinfo.c : \ ".\wrapperinfo.h"\ .\messages.rc : \ ".\MSG00001.bin"\ wrapper_3.5.26_src/src/c/Wrapper32.dsp100644 0 0 12262 12440202300 14663 0ustar 0 0 # Microsoft Developer Studio Project File - Name="Wrapper" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** ҏWȂł ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=Wrapper - Win32 Debug !MESSAGE ͗LҲ̧قł͂܂B ۼުĂނ邽߂ɂ NMAKE gpĂB !MESSAGE [Ҳ̧ق̴߰] ނgpĎsĂ !MESSAGE !MESSAGE NMAKE /f "Wrapper32.mak". !MESSAGE !MESSAGE NMAKE ̎sɍ\wł܂ !MESSAGE ײݏϸۂ̐ݒ`܂B: !MESSAGE !MESSAGE NMAKE /f "Wrapper32.mak" CFG="Wrapper - Win32 Debug" !MESSAGE !MESSAGE I”\ Ӱ: !MESSAGE !MESSAGE "Wrapper - Win32 Release" ("Win32 (x86) Console Application" p) !MESSAGE "Wrapper - Win32 Debug" ("Win32 (x86) Console Application" p) !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "Wrapper - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release32" # PROP Intermediate_Dir "Release32" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x411 /d "NDEBUG" # ADD RSC /l 0x411 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib shlwapi.lib /nologo /subsystem:console /machine:I386 /out:"../../bin/wrapper.exe" !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug32" # PROP Intermediate_Dir "Debug32" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEBUG" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x411 /d "_DEBUG" # ADD RSC /l 0x411 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib shlwapi.lib /nologo /subsystem:console /debug /machine:I386 /out:"../../bin/wrapper.exe" /pdbtype:sept !ENDIF # Begin Target # Name "Wrapper - Win32 Release" # Name "Wrapper - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\logger.c # End Source File # Begin Source File SOURCE=.\property.c # End Source File # Begin Source File SOURCE=.\wrapper.c # End Source File # Begin Source File SOURCE=.\wrapper_unix.c # End Source File # Begin Source File SOURCE=.\wrapper_win.c # End Source File # Begin Source File SOURCE=.\wrappereventloop.c # End Source File # Begin Source File SOURCE=.\wrapperinfo.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\logger.h # End Source File # Begin Source File SOURCE=.\messages.h # End Source File # Begin Source File SOURCE=.\property.h # End Source File # Begin Source File SOURCE=.\psapi.h # End Source File # Begin Source File SOURCE=.\resource.h # End Source File # Begin Source File SOURCE=.\wrapper.h # End Source File # Begin Source File SOURCE=.\wrapperinfo.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # Begin Source File SOURCE=.\MSG00001.bin # End Source File # Begin Source File SOURCE=.\wrapper.ico # End Source File # Begin Source File SOURCE=.\Wrapper32.rc # PROP Exclude_From_Build 1 # End Source File # End Group # Begin Source File SOURCE=.\messages.mc # End Source File # End Target # End Project wrapper_3.5.26_src/src/c/Wrapper32.dsw100644 0 0 1342 12440202300 14647 0ustar 0 0 Microsoft Developer Studio Workspace File, Format Version 6.00 # x: ܰ߰ ̧ ҏW܂͍폜Ȃł! ############################################################################### Project: "Wrapper"=.\Wrapper.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "WrapperJNI"=.\WrapperJNI.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### wrapper_3.5.26_src/src/c/Wrapper32.mak100644 0 0 17036 12440202300 14651 0ustar 0 0 # Microsoft Developer Studio Generated NMAKE File, Based on Wrapper32.dsp !IF "$(CFG)" == "" CFG=Wrapper - Win32 Debug !MESSAGE Build mode not specified. Defaulting to "Wrapper - Win32 Debug". !ENDIF !IF "$(CFG)" != "Wrapper - Win32 Release" && "$(CFG)" != "Wrapper - Win32 Debug" !MESSAGE The build target "$(CFG)" is invalid. !MESSAGE Usage: !MESSAGE !MESSAGE NMAKE /f "Wrapper32.mak" CFG="Wrapper - Win32 Debug" !MESSAGE !MESSAGE Valid build modes: !MESSAGE !MESSAGE "Wrapper - Win32 Release" ("Win32 (x86) Console Application") !MESSAGE "Wrapper - Win32 Debug" ("Win32 (x86) Console Application") !MESSAGE !ERROR Ivalid build mode. !ENDIF !IF "$(OS)" == "Windows_NT" NULL= !ELSE NULL=nul !ENDIF CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "Wrapper - Win32 Release" OUTDIR=.\Release32 INTDIR=.\Release32 ALL : "..\..\bin\wrapper.exe" CLEAN : -@erase "$(INTDIR)\logger.obj" -@erase "$(INTDIR)\property.obj" -@erase "$(INTDIR)\vc60.idb" -@erase "$(INTDIR)\wrapper.obj" -@erase "$(INTDIR)\Wrapper.res" -@erase "$(INTDIR)\wrapper_unix.obj" -@erase "$(INTDIR)\wrapper_win.obj" -@erase "$(INTDIR)\wrappereventloop.obj" -@erase "$(INTDIR)\wrapperinfo.obj" -@erase "..\..\bin\wrapper.exe" "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"$(INTDIR)\Wrapper32.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c RSC_PROJ=/l 0x409 /fo"$(INTDIR)\Wrapper.res" /d "NDEBUG" BSC32=bscmake.exe BSC32_FLAGS=/nologo /o"$(OUTDIR)\Wrapper32.bsc" BSC32_SBRS= \ LINK32=link.exe LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib shlwapi.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\wrapper.pdb" /machine:I386 /out:"../../bin/wrapper.exe" LINK32_OBJS= \ "$(INTDIR)\logger.obj" \ "$(INTDIR)\property.obj" \ "$(INTDIR)\wrapper.obj" \ "$(INTDIR)\wrapper_unix.obj" \ "$(INTDIR)\wrapper_win.obj" \ "$(INTDIR)\wrappereventloop.obj" \ "$(INTDIR)\wrapperinfo.obj" \ "$(INTDIR)\Wrapper.res" "..\..\bin\wrapper.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< $(LINK32_FLAGS) $(LINK32_OBJS) << !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" OUTDIR=.\Debug32 INTDIR=.\Debug32 # Begin Custom Macros OutDir=.\Debug32 # End Custom Macros ALL : "..\..\bin\wrapper.exe" "$(OUTDIR)\Wrapper32.bsc" CLEAN : -@erase "$(INTDIR)\logger.obj" -@erase "$(INTDIR)\logger.sbr" -@erase "$(INTDIR)\property.obj" -@erase "$(INTDIR)\property.sbr" -@erase "$(INTDIR)\vc60.idb" -@erase "$(INTDIR)\vc60.pdb" -@erase "$(INTDIR)\wrapper.obj" -@erase "$(INTDIR)\Wrapper.res" -@erase "$(INTDIR)\wrapper.sbr" -@erase "$(INTDIR)\wrapper_unix.obj" -@erase "$(INTDIR)\wrapper_unix.sbr" -@erase "$(INTDIR)\wrapper_win.obj" -@erase "$(INTDIR)\wrapper_win.sbr" -@erase "$(INTDIR)\wrappereventloop.obj" -@erase "$(INTDIR)\wrappereventloop.sbr" -@erase "$(INTDIR)\wrapperinfo.obj" -@erase "$(INTDIR)\wrapperinfo.sbr" -@erase "$(OUTDIR)\wrapper.pdb" -@erase "$(OUTDIR)\Wrapper32.bsc" -@erase "..\..\bin\wrapper.exe" -@erase "..\..\bin\wrapper.ilk" "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEBUG" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\Wrapper32.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c RSC_PROJ=/l 0x409 /fo"$(INTDIR)\Wrapper.res" /d "_DEBUG" BSC32=bscmake.exe BSC32_FLAGS=/nologo /o"$(OUTDIR)\Wrapper32.bsc" BSC32_SBRS= \ "$(INTDIR)\logger.sbr" \ "$(INTDIR)\property.sbr" \ "$(INTDIR)\wrapper.sbr" \ "$(INTDIR)\wrapper_unix.sbr" \ "$(INTDIR)\wrapper_win.sbr" \ "$(INTDIR)\wrappereventloop.sbr" \ "$(INTDIR)\wrapperinfo.sbr" "$(OUTDIR)\Wrapper32.bsc" : "$(OUTDIR)" $(BSC32_SBRS) $(BSC32) @<< $(BSC32_FLAGS) $(BSC32_SBRS) << LINK32=link.exe LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib shlwapi.lib /nologo /subsystem:console /incremental:yes /pdb:"$(OUTDIR)\wrapper.pdb" /debug /machine:I386 /out:"../../bin/wrapper.exe" /pdbtype:sept LINK32_OBJS= \ "$(INTDIR)\logger.obj" \ "$(INTDIR)\property.obj" \ "$(INTDIR)\wrapper.obj" \ "$(INTDIR)\wrapper_unix.obj" \ "$(INTDIR)\wrapper_win.obj" \ "$(INTDIR)\wrappereventloop.obj" \ "$(INTDIR)\wrapperinfo.obj" \ "$(INTDIR)\Wrapper.res" "..\..\bin\wrapper.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< $(LINK32_FLAGS) $(LINK32_OBJS) << !ENDIF .c{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .cpp{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .cxx{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .c{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << .cpp{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << .cxx{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << !IF "$(NO_EXTERNAL_DEPS)" != "1" !IF EXISTS("Wrapper32.dep") !INCLUDE "Wrapper32.dep" !ELSE !MESSAGE Warning: cannot find "Wrapper32.dep" !ENDIF !ENDIF !IF "$(CFG)" == "Wrapper - Win32 Release" || "$(CFG)" == "Wrapper - Win32 Debug" SOURCE=.\logger.c !IF "$(CFG)" == "Wrapper - Win32 Release" "$(INTDIR)\logger.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" "$(INTDIR)\logger.obj" "$(INTDIR)\logger.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\property.c !IF "$(CFG)" == "Wrapper - Win32 Release" "$(INTDIR)\property.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" "$(INTDIR)\property.obj" "$(INTDIR)\property.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\wrapper.c !IF "$(CFG)" == "Wrapper - Win32 Release" "$(INTDIR)\wrapper.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" "$(INTDIR)\wrapper.obj" "$(INTDIR)\wrapper.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\wrapper_unix.c !IF "$(CFG)" == "Wrapper - Win32 Release" "$(INTDIR)\wrapper_unix.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" "$(INTDIR)\wrapper_unix.obj" "$(INTDIR)\wrapper_unix.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\wrapper_win.c !IF "$(CFG)" == "Wrapper - Win32 Release" "$(INTDIR)\wrapper_win.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" "$(INTDIR)\wrapper_win.obj" "$(INTDIR)\wrapper_win.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\wrappereventloop.c !IF "$(CFG)" == "Wrapper - Win32 Release" "$(INTDIR)\wrappereventloop.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" "$(INTDIR)\wrappereventloop.obj" "$(INTDIR)\wrappereventloop.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\wrapperinfo.c !IF "$(CFG)" == "Wrapper - Win32 Release" "$(INTDIR)\wrapperinfo.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" "$(INTDIR)\wrapperinfo.obj" "$(INTDIR)\wrapperinfo.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\Wrapper.rc !IF "$(CFG)" == "Wrapper - Win32 Release" "$(INTDIR)\Wrapper.res" : $(SOURCE) "$(INTDIR)" $(RSC) /l 0x409 /fo"$(INTDIR)\Wrapper.res" /d "NDEBUG" $(SOURCE) !ELSEIF "$(CFG)" == "Wrapper - Win32 Debug" "$(INTDIR)\Wrapper.res" : $(SOURCE) "$(INTDIR)" $(RSC) /l 0x411 /fo"$(INTDIR)\Wrapper.res" /d "_DEBUG" $(SOURCE) !ENDIF !ENDIF wrapper_3.5.26_src/src/c/Wrapper32.plg100644 0 0 2745 12440202300 14644 0ustar 0 0

ނ۸

--------------------\: Wrapper - Win32 Debug--------------------

ײ

ꎞ̧ "C:\DOCUME~1\leif\LOCALS~1\Temp\RSP3E.tmp" 쐬A̓eL^܂ [ /nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEBUG" /FR"Debug32/" /Fp"Debug32/Wrapper32.pch" /YX /Fo"Debug32/" /Fd"Debug32/" /FD /GZ /c "C:\SourceForge\wrapper\src\c\wrapper.c" "C:\SourceForge\wrapper\src\c\wrapper_unix.c" "C:\SourceForge\wrapper\src\c\wrapper_win.c" "C:\SourceForge\wrapper\src\c\wrappereventloop.c" ] Creating command line "cl.exe @C:\DOCUME~1\leif\LOCALS~1\Temp\RSP3E.tmp" ꎞ̧ "C:\DOCUME~1\leif\LOCALS~1\Temp\RSP3F.tmp" 쐬A̓eL^܂ [ kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib shlwapi.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug32/wrapper.pdb" /debug /machine:I386 /out:"../../bin/wrapper.exe" /pdbtype:sept .\Debug32\logger.obj .\Debug32\property.obj .\Debug32\wrapper.obj .\Debug32\wrapper_unix.obj .\Debug32\wrapper_win.obj .\Debug32\wrappereventloop.obj .\Debug32\wrapperinfo.obj ] ײ "link.exe @C:\DOCUME~1\leif\LOCALS~1\Temp\RSP3F.tmp" ̍쐬

߯ ޳

ْ߲... wrapper.c wrapper_unix.c wrapper_win.c wrappereventloop.c ݸ...

wrapper.exe - װ 0Ax 0
wrapper_3.5.26_src/src/c/WrapperJNI32.dep.in100644 0 0 764 12440202300 15557 0ustar 0 0 # Microsoft Developer Studio Generated Dependency File, included by WrapperJNI32.mak .\wrapperinfo.c : \ ".\wrapperinfo.h"\ .\wrapperjni.c : \ ".\org_tanukisoftware_wrapper_WrapperManager.h"\ ".\wrapperinfo.h"\ ".\wrapperjni.h"\ "@msvc.home@\vc98\include\basetsd.h"\ "@jni.h@"\ "@jni_md.h@"\ .\wrapperjni_win.c : \ ".\org_tanukisoftware_wrapper_WrapperManager.h"\ ".\wrapperjni.h"\ "@msvc.home@\vc98\include\basetsd.h"\ "@jni.h@"\ "@jni_md.h@"\ wrapper_3.5.26_src/src/c/WrapperJNI32.dsp100644 0 0 11527 12440202300 15227 0ustar 0 0 # Microsoft Developer Studio Project File - Name="WrapperJNI" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** ҏWȂł ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 CFG=WrapperJNI - Win32 Debug !MESSAGE ͗LҲ̧قł͂܂B ۼުĂނ邽߂ɂ NMAKE gpĂB !MESSAGE [Ҳ̧ق̴߰] ނgpĎsĂ !MESSAGE !MESSAGE NMAKE /f "WrapperJNI.mak". !MESSAGE !MESSAGE NMAKE ̎sɍ\wł܂ !MESSAGE ײݏϸۂ̐ݒ`܂B: !MESSAGE !MESSAGE NMAKE /f "WrapperJNI.mak" CFG="WrapperJNI - Win32 Debug" !MESSAGE !MESSAGE I”\ Ӱ: !MESSAGE !MESSAGE "WrapperJNI - Win32 Release" ("Win32 (x86) Dynamic-Link Library" p) !MESSAGE "WrapperJNI - Win32 Debug" ("Win32 (x86) Dynamic-Link Library" p) !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "WrapperJNI - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "WrapperJNI___Win32_Release" # PROP BASE Intermediate_Dir "WrapperJNI___Win32_Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "WrapperJNI___Win32_Release32" # PROP Intermediate_Dir "WrapperJNI___Win32_Release32" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WRAPPERJNI_EXPORTS" /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /I "D:\Sun\j2sdk1.4.0_03\include\\" /I "D:\Sun\j2sdk1.4.0_03\include\win32\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WRAPPERJNI_EXPORTS" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x411 /d "NDEBUG" # ADD RSC /l 0x411 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../../lib/wrapper.dll" !ELSEIF "$(CFG)" == "WrapperJNI - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "WrapperJNI___Win32_Debug" # PROP BASE Intermediate_Dir "WrapperJNI___Win32_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "WrapperJNI___Win32_Debug32" # PROP Intermediate_Dir "WrapperJNI___Win32_Debug32" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WRAPPERJNI_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "D:\Sun\j2sdk1.4.0_03\include\\" /I "D:\Sun\j2sdk1.4.0_03\include\win32\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WRAPPERJNI_EXPORTS" /FR /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x411 /d "_DEBUG" # ADD RSC /l 0x411 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"../../lib/wrapper.dll" /pdbtype:sept !ENDIF # Begin Target # Name "WrapperJNI - Win32 Release" # Name "WrapperJNI - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=.\wrapperinfo.c # End Source File # Begin Source File SOURCE=.\wrapperjni.c # End Source File # Begin Source File SOURCE=.\wrapperjni_unix.c # End Source File # Begin Source File SOURCE=.\wrapperjni_win.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=.\org_tanukisoftware_wrapper_WrapperManager.h # End Source File # Begin Source File SOURCE=.\wrapperinfo.h # End Source File # Begin Source File SOURCE=.\wrapperjni.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project wrapper_3.5.26_src/src/c/WrapperJNI32.mak.in100644 0 0 14340 12440202300 15612 0ustar 0 0 # Microsoft Developer Studio Generated NMAKE File, Based on WrapperJNI32.dsp !IF "$(CFG)" == "" CFG=WrapperJNI - Win32 Debug !MESSAGE Build mode not specified. Defaulting to "WrapperJNI - Win32 Debug". !ENDIF !IF "$(CFG)" != "WrapperJNI - Win32 Release" && "$(CFG)" != "WrapperJNI - Win32 Debug" !MESSAGE The build target "$(CFG)" is invalid. !MESSAGE Usage: !MESSAGE !MESSAGE NMAKE /f "WrapperJNI32.mak" CFG="WrapperJNI - Win32 Debug" !MESSAGE !MESSAGE Valid build modes: !MESSAGE !MESSAGE "WrapperJNI - Win32 Release" ("Win32 (x86) Dynamic-Link Library") !MESSAGE "WrapperJNI - Win32 Debug" ("Win32 (x86) Dynamic-Link Library") !MESSAGE !ERROR Ivalid build mode. !ENDIF !IF "$(OS)" == "Windows_NT" NULL= !ELSE NULL=nul !ENDIF CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "WrapperJNI - Win32 Release" OUTDIR=.\WrapperJNI___Win32_Release32 INTDIR=.\WrapperJNI___Win32_Release32 ALL : "..\..\lib\wrapper.dll" CLEAN : -@erase "$(INTDIR)\vc60.idb" -@erase "$(INTDIR)\wrapperinfo.obj" -@erase "$(INTDIR)\wrapperjni.obj" -@erase "$(INTDIR)\wrapperjni_unix.obj" -@erase "$(INTDIR)\wrapperjni_win.obj" -@erase "$(OUTDIR)\wrapper.exp" -@erase "$(OUTDIR)\wrapper.lib" -@erase "..\..\lib\wrapper.dll" "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "@java.home@\include\\" /I "@java.home@\include\win32\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WRAPPERJNI_EXPORTS" /Fp"$(INTDIR)\WrapperJNI32.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 BSC32=bscmake.exe BSC32_FLAGS=/nologo /o"$(OUTDIR)\WrapperJNI32.bsc" BSC32_SBRS= \ LINK32=link.exe LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /pdb:"$(OUTDIR)\wrapper.pdb" /machine:I386 /out:"../../lib/wrapper.dll" /implib:"$(OUTDIR)\wrapper.lib" LINK32_OBJS= \ "$(INTDIR)\wrapperinfo.obj" \ "$(INTDIR)\wrapperjni.obj" \ "$(INTDIR)\wrapperjni_unix.obj" \ "$(INTDIR)\wrapperjni_win.obj" "..\..\lib\wrapper.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< $(LINK32_FLAGS) $(LINK32_OBJS) << !ELSEIF "$(CFG)" == "WrapperJNI - Win32 Debug" OUTDIR=.\WrapperJNI___Win32_Debug32 INTDIR=.\WrapperJNI___Win32_Debug32 # Begin Custom Macros OutDir=.\WrapperJNI___Win32_Debug32 # End Custom Macros ALL : "..\..\lib\wrapper.dll" "$(OUTDIR)\WrapperJNI32.bsc" CLEAN : -@erase "$(INTDIR)\vc60.idb" -@erase "$(INTDIR)\vc60.pdb" -@erase "$(INTDIR)\wrapperinfo.obj" -@erase "$(INTDIR)\wrapperinfo.sbr" -@erase "$(INTDIR)\wrapperjni.obj" -@erase "$(INTDIR)\wrapperjni.sbr" -@erase "$(INTDIR)\wrapperjni_unix.obj" -@erase "$(INTDIR)\wrapperjni_unix.sbr" -@erase "$(INTDIR)\wrapperjni_win.obj" -@erase "$(INTDIR)\wrapperjni_win.sbr" -@erase "$(OUTDIR)\wrapper.exp" -@erase "$(OUTDIR)\wrapper.lib" -@erase "$(OUTDIR)\wrapper.pdb" -@erase "$(OUTDIR)\WrapperJNI32.bsc" -@erase "..\..\lib\wrapper.dll" -@erase "..\..\lib\wrapper.ilk" "$(OUTDIR)" : if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=/nologo /MTd /W3 /Gm /GX /ZI /Od /I "@java.home@\include\\" /I "@java.home@\include\win32\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WRAPPERJNI_EXPORTS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\WrapperJNI32.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 BSC32=bscmake.exe BSC32_FLAGS=/nologo /o"$(OUTDIR)\WrapperJNI32.bsc" BSC32_SBRS= \ "$(INTDIR)\wrapperinfo.sbr" \ "$(INTDIR)\wrapperjni.sbr" \ "$(INTDIR)\wrapperjni_unix.sbr" \ "$(INTDIR)\wrapperjni_win.sbr" "$(OUTDIR)\WrapperJNI32.bsc" : "$(OUTDIR)" $(BSC32_SBRS) $(BSC32) @<< $(BSC32_FLAGS) $(BSC32_SBRS) << LINK32=link.exe LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\wrapper.pdb" /debug /machine:I386 /out:"../../lib/wrapper.dll" /implib:"$(OUTDIR)\wrapper.lib" /pdbtype:sept LINK32_OBJS= \ "$(INTDIR)\wrapperinfo.obj" \ "$(INTDIR)\wrapperjni.obj" \ "$(INTDIR)\wrapperjni_unix.obj" \ "$(INTDIR)\wrapperjni_win.obj" "..\..\lib\wrapper.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< $(LINK32_FLAGS) $(LINK32_OBJS) << !ENDIF .c{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .cpp{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .cxx{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .c{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << .cpp{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << .cxx{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << !IF "$(NO_EXTERNAL_DEPS)" != "1" !IF EXISTS("WrapperJNI32.dep") !INCLUDE "WrapperJNI32.dep" !ELSE !MESSAGE Warning: cannot find "WrapperJNI32.dep" !ENDIF !ENDIF !IF "$(CFG)" == "WrapperJNI - Win32 Release" || "$(CFG)" == "WrapperJNI - Win32 Debug" SOURCE=.\wrapperinfo.c !IF "$(CFG)" == "WrapperJNI - Win32 Release" "$(INTDIR)\wrapperinfo.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "WrapperJNI - Win32 Debug" "$(INTDIR)\wrapperinfo.obj" "$(INTDIR)\wrapperinfo.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\wrapperjni.c !IF "$(CFG)" == "WrapperJNI - Win32 Release" "$(INTDIR)\wrapperjni.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "WrapperJNI - Win32 Debug" "$(INTDIR)\wrapperjni.obj" "$(INTDIR)\wrapperjni.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\wrapperjni_unix.c !IF "$(CFG)" == "WrapperJNI - Win32 Release" "$(INTDIR)\wrapperjni_unix.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "WrapperJNI - Win32 Debug" "$(INTDIR)\wrapperjni_unix.obj" "$(INTDIR)\wrapperjni_unix.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF SOURCE=.\wrapperjni_win.c !IF "$(CFG)" == "WrapperJNI - Win32 Release" "$(INTDIR)\wrapperjni_win.obj" : $(SOURCE) "$(INTDIR)" !ELSEIF "$(CFG)" == "WrapperJNI - Win32 Debug" "$(INTDIR)\wrapperjni_win.obj" "$(INTDIR)\wrapperjni_win.sbr" : $(SOURCE) "$(INTDIR)" !ENDIF !ENDIF wrapper_3.5.26_src/src/c/WrapperJNI32.plg100644 0 0 3475 12440202300 15206 0ustar 0 0

ނ۸

--------------------\: WrapperJNI - Win32 Debug--------------------

ײ

ꎞ̧ "C:\DOCUME~1\leif\LOCALS~1\Temp\RSP321.tmp" 쐬A̓eL^܂ [ /nologo /MTd /W3 /Gm /GX /ZI /Od /I "C:\Sun\j2sdk1.4.2_08\include\\" /I "C:\Sun\j2sdk1.4.2_08\include\win32\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WRAPPERJNI_EXPORTS" /FR"WrapperJNI___Win32_Debug32/" /Fp"WrapperJNI___Win32_Debug32/WrapperJNI32.pch" /YX /Fo"WrapperJNI___Win32_Debug32/" /Fd"WrapperJNI___Win32_Debug32/" /FD /GZ /c "D:\SourceForge\wrapper\src\c\wrapperinfo.c" "D:\SourceForge\wrapper\src\c\wrapperjni.c" "D:\SourceForge\wrapper\src\c\wrapperjni_unix.c" "D:\SourceForge\wrapper\src\c\wrapperjni_win.c" ] Creating command line "cl.exe @C:\DOCUME~1\leif\LOCALS~1\Temp\RSP321.tmp" ꎞ̧ "C:\DOCUME~1\leif\LOCALS~1\Temp\RSP322.tmp" 쐬A̓eL^܂ [ kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:yes /pdb:"WrapperJNI___Win32_Debug32/wrapper.pdb" /debug /machine:I386 /out:"../../lib/wrapper.dll" /implib:"WrapperJNI___Win32_Debug32/wrapper.lib" /pdbtype:sept .\WrapperJNI___Win32_Debug32\wrapperinfo.obj .\WrapperJNI___Win32_Debug32\wrapperjni.obj .\WrapperJNI___Win32_Debug32\wrapperjni_unix.obj .\WrapperJNI___Win32_Debug32\wrapperjni_win.obj ] ײ "link.exe @C:\DOCUME~1\leif\LOCALS~1\Temp\RSP322.tmp" ̍쐬

߯ ޳

ْ߲... wrapperinfo.c wrapperjni.c wrapperjni_unix.c wrapperjni_win.c ݸ... ײ WrapperJNI___Win32_Debug32/wrapper.lib Ƶ޼ު WrapperJNI___Win32_Debug32/wrapper.exp 쐬

wrapper.dll - װ 0Ax 0
wrapper_3.5.26_src/src/c/logger.c100644 0 0 354737 12440202301 14052 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * Author: * Johan Sorlin * Leif Mortenson */ #include #include #include #include #include #include #include #include #include "logger_file.h" #ifdef WIN32 #include #include #include #include #include #include #include "messages.h" /* MS Visual Studio 8 went and deprecated the POXIX names for functions. * Fixing them all would be a big headache for UNIX versions. */ #pragma warning(disable : 4996) /* Defines for MS Visual Studio 6 */ #ifndef _INTPTR_T_DEFINED typedef long intptr_t; #define _INTPTR_T_DEFINED #endif #else #include #include #include #include #include #if defined(SOLARIS) #include #include #elif defined(AIX) || defined(HPUX) || defined(MACOSX) || defined(OSF1) #elif defined(IRIX) #elif defined(FREEBSD) #include #include #else /* LINUX */ #include #endif #endif #include "wrapper_i18n.h" #include "logger.h" #ifndef TRUE #define TRUE -1 #endif #ifndef FALSE #define FALSE 0 #endif const TCHAR* defaultLogFile = TEXT("wrapper.log"); /* Global data for logger */ /* Maximum number of milliseconds that a log write can take before we show a warning. */ int logPrintfWarnThreshold = 0; /* Number of millisecoonds which the previous log message took to process. */ time_t previousLogLag; /* Keep track of when the last log entry was made so we can show the information in the log. */ time_t previousNow; int previousNowMillis; /* Initialize all log levels to unknown until they are set */ int currentConsoleLevel = LEVEL_UNKNOWN; int currentLogfileLevel = LEVEL_UNKNOWN; int currentLoginfoLevel = LEVEL_UNKNOWN; int currentLogSplitMessages = FALSE; /* Default syslog facility is LOG_USER */ int currentLogfacilityLevel = LOG_USER; /* Callback notified whenever the active logfile changes. */ void (*logFileChangedCallback)(const TCHAR *logFile); /* Stores a carefully malloced filename of the most recent log file change. This value is only set in log_printf(), and only cleared in maintainLogger(). */ TCHAR *pendingLogFileChange = NULL; int logPauseTime = -1; int logBufferGrowth = FALSE; TCHAR *logFilePath; /* Size of the currentLogFileName and workLogFileName buffers. */ size_t currentLogFileNameSize; TCHAR *currentLogFileName; TCHAR *workLogFileName; int logFileRollMode = ROLL_MODE_SIZE; int logFileUmask = 0022; TCHAR *logLevelNames[] = { TEXT("NONE "), TEXT("DEBUG "), TEXT("INFO "), TEXT("STATUS"), TEXT("WARN "), TEXT("ERROR "), TEXT("FATAL "), TEXT("ADVICE"), TEXT("NOTICE") }; #ifdef WIN32 TCHAR *defaultLoginfoSourceName = TEXT("wrapper"); TCHAR *loginfoSourceName = NULL; #else char *defaultLoginfoSourceName = "wrapper"; char *loginfoSourceName = NULL; #endif int logFileMaxSize = -1; int logFileMaxLogFiles = -1; TCHAR *logFilePurgePattern = NULL; int logFilePurgeSortMode = LOGGER_FILE_SORT_MODE_TIMES; TCHAR logFileLastNowDate[9]; /* Defualt formats (Must be 4 chars) */ TCHAR consoleFormat[32]; TCHAR logfileFormat[32]; /* Flag to keep track of whether the console output should be flushed or not. */ int consoleFlush = FALSE; #ifdef WIN32 /* Flag to keep track of whether we should write directly to the console or not. */ int consoleDirect = TRUE; #endif /* Flags to contol where error log level output goes to the console. */ int consoleFatalToStdErr = TRUE; int consoleErrorToStdErr = TRUE; int consoleWarnToStdErr = FALSE; /* Number of seconds since the Wrapper was launched. */ int uptimeSeconds = 0; /* TRUE once the uptime is so large that it is meaningless. */ int uptimeFlipped = FALSE; /* Internal function declaration */ #ifdef WIN32 void sendEventlogMessage( int source_id, int level, const TCHAR *szBuff ); #else void sendLoginfoMessage( int source_id, int level, const TCHAR *szBuff ); #endif #ifdef WIN32 int writeToConsole( HANDLE hdl, TCHAR *lpszFmt, ...); #endif void checkAndRollLogs(const TCHAR *nowDate); int lockLoggingMutex(); int releaseLoggingMutex(); /* Any log messages generated within signal handlers must be stored until we * have left the signal handler to avoid deadlocks in the logging code. * Messages are stored in a round robin buffer of log messages until * maintainLogger is next called. * When we are inside of a signal, and thus when calling log_printf_queue, * we know that it is safe to modify the queue as needed. But it is possible * that a signal could be fired while we are in maintainLogger, so case is * taken to make sure that volatile changes are only made in log_printf_queue. */ #define QUEUE_SIZE 20 /* The size of QUEUED_BUFFER_SIZE_USABLE is arbitrary as the largest size which can be logged in full, * but to avoid crashes due to a bug in the HPUX libc (version < 1403), the length of the buffer passed to _vsntprintf must have a length of 1 + N, where N is a multiple of 8. */ #define QUEUED_BUFFER_SIZE_USABLE (512 + 1) #define QUEUED_BUFFER_SIZE (QUEUED_BUFFER_SIZE_USABLE + 4) #if defined(UNICODE) && !defined(WIN32) TCHAR formatMessages[WRAPPER_THREAD_COUNT][QUEUED_BUFFER_SIZE]; #endif int queueWrapped[WRAPPER_THREAD_COUNT]; int queueWriteIndex[WRAPPER_THREAD_COUNT]; int queueReadIndex[WRAPPER_THREAD_COUNT]; TCHAR queueMessages[WRAPPER_THREAD_COUNT][QUEUE_SIZE][QUEUED_BUFFER_SIZE]; int queueSourceIds[WRAPPER_THREAD_COUNT][QUEUE_SIZE]; int queueLevels[WRAPPER_THREAD_COUNT][QUEUE_SIZE]; /* Thread specific work buffers. */ int threadSets[WRAPPER_THREAD_COUNT]; #ifdef WIN32 DWORD threadIds[WRAPPER_THREAD_COUNT]; #else pthread_t threadIds[WRAPPER_THREAD_COUNT]; #endif TCHAR *threadMessageBuffer = NULL; size_t threadMessageBufferSize = 0; TCHAR *threadPrintBuffer = NULL; size_t threadPrintBufferSize = 0; #ifdef WIN32 int launcherSource = FALSE; #endif /* Flag which gets set when a log entry is written to the log file. */ int logFileAccessed = FALSE; /* Logger file pointer. It is kept open under high log loads but closed whenever it has been idle. */ FILE *logfileFP = NULL; /** Flag which controls whether or not the logfile is auto flushed after each line. */ int autoFlushLogfile = 0; /** Flag which controls whether or not the logfile is auto closed after each line. */ int autoCloseLogfile = 0; /* The number of lines sent to the log file since the getLogfileActivity method was last called. */ DWORD logfileActivityCount = 0; /* Mutex for syncronization of the log_printf function. */ #ifdef WIN32 HANDLE log_printfMutexHandle = NULL; #else pthread_mutex_t log_printfMutex = PTHREAD_MUTEX_INITIALIZER; #endif void outOfMemory(const TCHAR *context, int id) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Out of memory (%s%02d). %s"), context, id, getLastErrorText()); } /* This can be called from within logging code that would otherwise get stuck in recursion. * Log to the console exactly when it happens and then also try to get it into the log * file at the next oportunity. */ void outOfMemoryQueued(const TCHAR *context, int id) { _tprintf(TEXT("Out of memory (%s%02d). %s\n"), context, id, getLastErrorText()); log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Out of memory (%s%02d). %s"), context, id, getLastErrorText()); } #ifdef _DEBUG /** * Used to dump memory directly to the log file in both HEX and readable format. * Useful in debugging applications to track down memory overflows etc. * * @param label A label that will be prepended on all lines of output. * @param memory The memory to be dumped. * @param len The length of the memory to be dumped. */ void log_dumpHex(TCHAR *label, TCHAR *memory, size_t len) { TCHAR *buffer; TCHAR *pos; size_t i; int c; buffer = malloc(sizeof(TCHAR) * (len * 3 + 1)); if (!buffer) { outOfMemory(TEXT("DH"), 1); } pos = buffer; for (i = 0; i < len; i++) { c = memory[i] & 0xff; _sntprintf(pos, 4, TEXT("%02x "), c); pos += 3; } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("%s (HEX) = %s"), label, buffer); pos = buffer; for (i = 0; i < len; i++) { c = memory[i] & 0xff; if (c == 0) { _sntprintf(pos, 4, TEXT("\\0 ")); } else if (c <= 26) { _sntprintf(pos, 4, TEXT("\\%c "), TEXT('a') + c - 1); } else if (c < 127) { _sntprintf(pos, 4, TEXT("%c "), c); } else { _sntprintf(pos, 4, TEXT(". ")); } pos += 3; } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("%s (CHAR) = %s"), label, buffer); free(buffer); } #endif void invalidMultiByteSequence(const TCHAR *context, int id) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Invalid multibyte Sequence found in (%s%02d). %s"), context, id, getLastErrorText()); } /** * Replaces one token with another. The length of the new token must be equal * to or less than that of the old token. * * newToken may be null, implying "". */ TCHAR *replaceStringLongWithShort(TCHAR *string, const TCHAR *oldToken, const TCHAR *newToken) { size_t oldLen = _tcslen(oldToken); size_t newLen; TCHAR *in = string; TCHAR *out = string; if (newToken) { newLen = _tcslen(newToken); } else { newLen = 0; } /* Assertion check. */ if (newLen > oldLen) { return string; } while (in[0] != L'\0') { if (_tcsncmp(in, oldToken, oldLen) == 0) { /* Found the oldToken. Replace it with the new. */ if (newLen > 0) { _tcsncpy(out, newToken, newLen); } in += oldLen; out += newLen; } else { out[0] = in[0]; in++; out++; } } out[0] = L'\0'; return string; } /** * Initializes the logger. Returns 0 if the operation was successful. */ int initLogging(void (*logFileChanged)(const TCHAR *logFile)) { int threadId, i; logFileChangedCallback = logFileChanged; #ifdef WIN32 if (!(log_printfMutexHandle = CreateMutex(NULL, FALSE, NULL))) { _tprintf(TEXT("Failed to create logging mutex. %s\n"), getLastErrorText()); return 1; } #endif logPauseTime = -1; loginfoSourceName = defaultLoginfoSourceName; logFileAccessed = FALSE; logFileLastNowDate[0] = L'\0'; for ( threadId = 0; threadId < WRAPPER_THREAD_COUNT; threadId++ ) { threadSets[threadId] = FALSE; /* threadIds[threadId] = 0; */ #if defined(UNICODE) && !defined(WIN32) formatMessages[threadId][0] = TEXT('\0'); #endif for ( i = 0; i < QUEUE_SIZE; i++ ) { queueWrapped[threadId] = 0; queueWriteIndex[threadId] = 0; queueReadIndex[threadId] = 0; queueMessages[threadId][i][0] = TEXT('\0'); queueSourceIds[threadId][i] = 0; queueLevels[threadId][i] = 0; } } return 0; } /** * Disposes of any logging resouces prior to shutdown. */ int disposeLogging() { #ifdef WIN32 #ifdef WRAPPERW int i; #endif /* Always call maintain logger once to make sure that all queued messages are logged before we exit. */ maintainLogger(); if (log_printfMutexHandle) { if (!CloseHandle(log_printfMutexHandle)) { _tprintf(TEXT("Unable to close Logging Mutex handle. %s\n"), getLastErrorText()); return 1; } } #ifdef WRAPPERW for (i = 0; i < dialogLogEntries; i++) { free(dialogLogs[i]); dialogLogs[i] = NULL; } free(dialogLogs); dialogLogs = NULL; #endif #endif if (threadPrintBuffer && threadPrintBufferSize > 0) { free(threadPrintBuffer); threadPrintBuffer = NULL; threadPrintBufferSize = 0; } if (threadMessageBuffer && threadMessageBufferSize > 0) { free(threadMessageBuffer); threadMessageBuffer = NULL; threadMessageBufferSize = 0; } if (logFilePath) { free(logFilePath); logFilePath = NULL; } if (currentLogFileName) { free(currentLogFileName); currentLogFileName = NULL; } if (workLogFileName) { free(workLogFileName); workLogFileName = NULL; } if ((loginfoSourceName != defaultLoginfoSourceName) && (loginfoSourceName != NULL)) { free(loginfoSourceName); loginfoSourceName = NULL; } if (logfileFP) { fclose(logfileFP); logfileFP = NULL; } return 0; } /** Registers the calling thread so it can be recognized when it calls * again later. */ void logRegisterThread( int thread_id ) { #ifdef WIN32 DWORD threadId; threadId = GetCurrentThreadId(); #else pthread_t threadId; threadId = pthread_self(); #endif #ifdef _DEBUG _tprintf(TEXT("logRegisterThread(%d)\n"), thread_id); #endif if ( thread_id >= 0 && thread_id < WRAPPER_THREAD_COUNT ) { threadSets[thread_id] = TRUE; threadIds[thread_id] = threadId; #ifdef _DEBUG _tprintf(TEXT("logRegisterThread(%d) found\n"), thread_id); #endif } } int getThreadId() { int i; #ifdef WIN32 DWORD threadId; threadId = GetCurrentThreadId(); #else pthread_t threadId; threadId = pthread_self(); #endif /*_tprintf(TEXT("threadId=%lu\n"), threadId );*/ for ( i = 0; i < WRAPPER_THREAD_COUNT; i++ ) { #ifdef WIN32 if (threadSets[i] && (threadIds[i] == threadId)) { #else if (threadSets[i] && pthread_equal(threadIds[i], threadId)) { #endif return i; } } _tprintf( TEXT("WARNING - Encountered an unknown thread %ld in getThreadId().\n"), (long int)threadId ); return 0; /* WRAPPER_THREAD_SIGNAL */ } int getLogfileRollModeForName( const TCHAR *logfileRollName ) { if (strcmpIgnoreCase(logfileRollName, TEXT("NONE")) == 0) { return ROLL_MODE_NONE; } else if (strcmpIgnoreCase(logfileRollName, TEXT("SIZE")) == 0) { return ROLL_MODE_SIZE; } else if (strcmpIgnoreCase(logfileRollName, TEXT("WRAPPER")) == 0) { return ROLL_MODE_WRAPPER; } else if (strcmpIgnoreCase(logfileRollName, TEXT("JVM")) == 0) { return ROLL_MODE_JVM; } else if (strcmpIgnoreCase(logfileRollName, TEXT("SIZE_OR_WRAPPER")) == 0) { return ROLL_MODE_SIZE_OR_WRAPPER; } else if (strcmpIgnoreCase(logfileRollName, TEXT("SIZE_OR_JVM")) == 0) { return ROLL_MODE_SIZE_OR_JVM; } else if (strcmpIgnoreCase(logfileRollName, TEXT("DATE")) == 0) { return ROLL_MODE_DATE; } else { return ROLL_MODE_UNKNOWN; } } int getLogLevelForName( const TCHAR *logLevelName ) { if (strcmpIgnoreCase(logLevelName, TEXT("NONE")) == 0) { return LEVEL_NONE; } else if (strcmpIgnoreCase(logLevelName, TEXT("NOTICE")) == 0) { return LEVEL_NOTICE; } else if (strcmpIgnoreCase(logLevelName, TEXT("ADVICE")) == 0) { return LEVEL_ADVICE; } else if (strcmpIgnoreCase(logLevelName, TEXT("FATAL")) == 0) { return LEVEL_FATAL; } else if (strcmpIgnoreCase(logLevelName, TEXT("ERROR")) == 0) { return LEVEL_ERROR; } else if (strcmpIgnoreCase(logLevelName, TEXT("WARN")) == 0) { return LEVEL_WARN; } else if (strcmpIgnoreCase(logLevelName, TEXT("STATUS")) == 0) { return LEVEL_STATUS; } else if (strcmpIgnoreCase(logLevelName, TEXT("INFO")) == 0) { return LEVEL_INFO; } else if (strcmpIgnoreCase(logLevelName, TEXT("DEBUG")) == 0) { return LEVEL_DEBUG; } else { return LEVEL_UNKNOWN; } } #ifndef WIN32 int getLogFacilityForName( const TCHAR *logFacilityName ) { if (strcmpIgnoreCase(logFacilityName, TEXT("USER")) == 0) { return LOG_USER; } else if (strcmpIgnoreCase(logFacilityName, TEXT("LOCAL0")) == 0) { return LOG_LOCAL0; } else if (strcmpIgnoreCase(logFacilityName, TEXT("LOCAL1")) == 0) { return LOG_LOCAL1; } else if (strcmpIgnoreCase(logFacilityName, TEXT("LOCAL2")) == 0) { return LOG_LOCAL2; } else if (strcmpIgnoreCase(logFacilityName, TEXT("LOCAL3")) == 0) { return LOG_LOCAL3; } else if (strcmpIgnoreCase(logFacilityName, TEXT("LOCAL4")) == 0) { return LOG_LOCAL4; } else if (strcmpIgnoreCase(logFacilityName, TEXT("LOCAL5")) == 0) { return LOG_LOCAL5; } else if (strcmpIgnoreCase(logFacilityName, TEXT("LOCAL6")) == 0) { return LOG_LOCAL6; } else if (strcmpIgnoreCase(logFacilityName, TEXT("LOCAL7")) == 0) { return LOG_LOCAL7; } else { return LOG_USER; } } #endif /** * Sets the number of milliseconds to allow logging to take before a warning is logged. * Defaults to 0 for no limit. Possible values 0 to 3600000. * * @param threshold Warning threashold. */ void setLogWarningThreshold(int threshold) { logPrintfWarnThreshold = __max(__min(threshold, 3600000), 0); } /** * Sets the log levels to a silence so we never output anything. */ void setSilentLogLevels() { setConsoleLogLevelInt(LEVEL_NONE); #ifdef WRAPPERW setDialogLogLevelInt(LEVEL_NONE); #endif setLogfileLevelInt(LEVEL_NONE); setSyslogLevelInt(LEVEL_NONE); } /** * Sets the console log levels to a simple format for help and usage messages. */ void setSimpleLogLevels() { /* Force the log levels to control output. */ setConsoleLogFormat(TEXT("M")); setConsoleLogLevelInt(LEVEL_INFO); setLogfileLevelInt(LEVEL_NONE); setSyslogLevelInt(LEVEL_NONE); } #ifdef WIN32 /** * This sets a flag which tells the logger that alternate source labels should be used to indicate that the current process is a launcher. */ void setLauncherSource() { launcherSource = TRUE; } #endif /* Logfile functions */ int isLogfileAccessed() { return logFileAccessed; } /** * Sets the log file to be used. If the specified file is not absolute then * it will be resolved into an absolute path. If there are any problems with * the path, like a directory not existing then the call will fail and the * cause will be written to the existing log. * * @param log_file_path Log file to start using. * @param workingDir The current working directory, used for relative paths. * This will be NULL if this is part of the bootstrap process, * in which case we should not attempt to resolve the absolute * path. * @param preload TRUE if called as part of the preload process. We use this to * suppress double warnings. * * @return TRUE if there were any problems. */ extern int setLogfilePath(const TCHAR *log_file_path, const TCHAR *workingDir, int preload) { size_t len = _tcslen(log_file_path); #ifdef WIN32 TCHAR *c; #endif /* The currentLogFileNameSize is the size of log_file_path + 10 ("." + a roll number) + 1 (NULL). */ currentLogFileNameSize = len + 10 + 1; if (logFilePath) { free(logFilePath); free(currentLogFileName); free(workLogFileName); } logFilePath = NULL; currentLogFileName = NULL; workLogFileName = NULL; logFilePath = malloc(sizeof(TCHAR) * (len + 1)); if (!logFilePath) { outOfMemoryQueued(TEXT("SLP"), 1); return TRUE; } _tcsncpy(logFilePath, log_file_path, len + 1); currentLogFileName = malloc(sizeof(TCHAR) * currentLogFileNameSize); if (!currentLogFileName) { outOfMemoryQueued(TEXT("SLP"), 2); free(logFilePath); logFilePath = NULL; return TRUE; } currentLogFileName[0] = TEXT('\0'); workLogFileName = malloc(sizeof(TCHAR) * currentLogFileNameSize); if (!workLogFileName) { outOfMemoryQueued(TEXT("SLP"), 3); free(logFilePath); logFilePath = NULL; free(currentLogFileName); currentLogFileNameSize = 0; currentLogFileName = NULL; return TRUE; } workLogFileName[0] = TEXT('\0'); #ifdef WIN32 /* To avoid problems on some windows systems, the '/' characters must * be replaced by '\' characters in the specified path. */ c = (TCHAR *)logFilePath; while((c = _tcschr(c, TEXT('/'))) != NULL) { c[0] = TEXT('\\'); } #endif return FALSE; } /** * Returns the default logfile. */ const TCHAR *getDefaultLogfilePath() { return defaultLogFile; } /** * Returns a reference to the currect log file path. * This return value may be changed at any time if the log file is rolled. */ const TCHAR *getLogfilePath() { return logFilePath; } /** * Returns a snapshot of the current log file path. This call safely gets the current path * and returns a copy. It is the responsibility of the caller to free up the memory on * return. Could return null if there was an error. */ TCHAR *getCurrentLogfilePath() { TCHAR *logFileCopy; /* Lock the logging mutex. */ if (lockLoggingMutex()) { return NULL; } /* We should always have a current log file name here because there will be at least one line of log output before this is called. * If that is false then we will return an empty length, but valid, string. */ logFileCopy = malloc(sizeof(TCHAR) * (_tcslen(currentLogFileName) + 1)); if (!logFileCopy) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("CLFP1")); } else { _tcsncpy(logFileCopy, currentLogFileName, _tcslen(currentLogFileName) + 1); } /* Release the lock we have on the logging mutex so that other threads can get in. */ if (releaseLoggingMutex()) { if (logFileCopy) { free(logFileCopy); } return NULL; } return logFileCopy; } /** * Check the directory of the current logfile path to make sure it is writable. * If there are any problems, log a warning. * * @return TRUE if there were any problems. */ int checkLogfileDir() { size_t len; TCHAR *c; TCHAR *logFileDir; TCHAR *testfile; int fd; len = _tcslen(logFilePath) + 1; logFileDir = malloc(len * sizeof(TCHAR)); if (!logFileDir) { outOfMemory(TEXT("CLD"), 1); return TRUE; } _tcsncpy(logFileDir, logFilePath, len); #ifdef WIN32 c = _tcsrchr(logFileDir, TEXT('\\')); #else c = _tcsrchr(logFileDir, TEXT('/')); #endif if (c) { c[0] = TEXT('\0'); /* We want to try writing a test file to the configured log directory to make sure it is writable. */ len = _tcslen(logFileDir) + 23 + 1 + 1000; testfile = malloc(len * sizeof(TCHAR)); if (!testfile) { outOfMemory(TEXT("CLD"), 1); free(logFileDir); return TRUE; } _sntprintf(testfile, len, TEXT("%s%c.wrapper_test-%.4d%.4d"), logFileDir, #ifdef WIN32 TEXT('\\'), #else TEXT('/'), #endif rand() % 9999, rand() % 9999); if ((fd = _topen(testfile, O_WRONLY | O_CREAT | O_EXCL #ifdef WIN32 , _S_IWRITE #else , S_IRUSR | S_IWUSR #endif )) == -1) { if (errno == EACCES) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to write to the configured log directory: %s (%s)\n The Wrapper may also have problems writing or rolling the log file.\n Please make sure that the current user has read/write access."), logFileDir, getLastErrorText()); } else if (errno == ENOENT) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to write to the configured log directory: %s (%s)\n The directory does not exist."), logFileDir, getLastErrorText()); } } else { /* Successfully wrote the temp file. */ #ifdef WIN32 _close(fd); #else close(fd); #endif if (_tremove(testfile)) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to remove temporary file: %s (%s)\n The Wrapper may also have problems writing or rolling the log file.\n Please make sure that the current user has read/write access."), testfile, getLastErrorText()); } } free(testfile); } free(logFileDir); return FALSE; } /** * This method will wiat for the specified number of seconds. It is only meant for special * uses within the logging code as it does not itself log any output in a correct way. */ void logSleep(int ms) { #ifdef WIN32 Sleep(ms); #else /* We want to use nanosleep if it is available, but make it possible for the user to build a version that uses usleep if they want. usleep does not behave nicely with signals thrown while sleeping. This was the believed cause of a hang experienced on one Solaris system. */ #ifdef USE_USLEEP usleep(ms * 1000); /* microseconds */ #else struct timespec ts; if (ms >= 1000) { ts.tv_sec = (ms * 1000000) / 1000000000; ts.tv_nsec = (ms * 1000000) % 1000000000; /* nanoseconds */ } else { ts.tv_sec = 0; ts.tv_nsec = ms * 1000000; /* nanoseconds */ } if (nanosleep(&ts, NULL)) { if (errno == EINTR) { return; } else if (errno == EAGAIN) { /* On 64-bit AIX this happens once on shutdown. */ return; } else { _tprintf(TEXT("nanosleep(%dms) failed. \n"), ms, getLastErrorText()); } } #endif #endif } /** * Used for testing to set a pause into the next log entry made. * * @param pauseTime Number of seconds to pause, 0 pauses indefinitely. */ void setPauseTime(int pauseTime) { logPauseTime = pauseTime; } /** * Set to true to cause changes in internal buffer sizes to be logged. Useful for debugging. * * @param log TRUE if changes should be logged. */ void setLogBufferGrowth(int log) { logBufferGrowth = log; } void setLogfileRollMode( int log_file_roll_mode ) { logFileRollMode = log_file_roll_mode; } int getLogfileRollMode() { return logFileRollMode; } void setLogfileUmask( int log_file_umask ) { logFileUmask = log_file_umask; } void setLogfileFormat( const TCHAR *log_file_format ) { if ( log_file_format != NULL ) { _tcsncpy( logfileFormat, log_file_format, 32 ); /* We only want to time logging if it is needed. */ if ((logPrintfWarnThreshold <= 0) && (_tcschr(log_file_format, TEXT('G')))) { logPrintfWarnThreshold = 99999999; } } } void setLogfileLevelInt( int log_file_level ) { currentLogfileLevel = log_file_level; } int getLogfileLevelInt() { return currentLogfileLevel; } void setLogfileLevel( const TCHAR *log_file_level ) { setLogfileLevelInt(getLogLevelForName(log_file_level)); } void setLogfileMaxFileSize( const TCHAR *max_file_size ) { int multiple, i, newLength; TCHAR *tmpFileSizeBuff; TCHAR chr; if ( max_file_size != NULL ) { /* Allocate buffer */ tmpFileSizeBuff = malloc(sizeof(TCHAR) * (_tcslen( max_file_size ) + 1)); if (!tmpFileSizeBuff) { outOfMemoryQueued(TEXT("SLMFS"), 1); return; } /* Generate multiple and remove unwanted chars */ multiple = 1; newLength = 0; for( i = 0; i < (int)_tcslen(max_file_size); i++ ) { chr = max_file_size[i]; switch( chr ) { case TEXT('k'): /* Kilobytes */ case TEXT('K'): multiple = 1024; break; case TEXT('M'): /* Megabytes */ case TEXT('m'): multiple = 1048576; break; } if( (chr >= TEXT('0') && chr <= TEXT('9')) || (chr == TEXT('-')) ) tmpFileSizeBuff[newLength++] = max_file_size[i]; } tmpFileSizeBuff[newLength] = TEXT('\0');/* Crop string */ logFileMaxSize = _ttoi( tmpFileSizeBuff ); if( logFileMaxSize > 0 ) logFileMaxSize *= multiple; /* Free memory */ free( tmpFileSizeBuff ); tmpFileSizeBuff = NULL; if ((logFileMaxSize > 0) && (logFileMaxSize < 1024)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT( "wrapper.logfile.maxsize must be 0 or at least 1024. Changing to %d."), logFileMaxSize); logFileMaxSize = 1024; } } } void setLogfileMaxFileSizeInt( int max_file_size ) { logFileMaxSize = max_file_size; } void setLogfileMaxLogFiles( int max_log_files ) { logFileMaxLogFiles = max_log_files; } void setLogfilePurgePattern(const TCHAR *pattern) { size_t len; if (logFilePurgePattern) { free(logFilePurgePattern); logFilePurgePattern = NULL; } len = _tcslen(pattern); if (len > 0) { logFilePurgePattern = malloc(sizeof(TCHAR) * (len + 1)); if (!logFilePurgePattern) { outOfMemoryQueued(TEXT("SLPP"), 1); return; } _tcsncpy(logFilePurgePattern, pattern, len + 1); } } void setLogfilePurgeSortMode(int sortMode) { logFilePurgeSortMode = sortMode; } /** Returns the number of lines of log file activity since the last call. */ DWORD getLogfileActivity() { DWORD logfileLines; /* Don't worry about synchronization here. Any errors are not critical the way this is used. */ logfileLines = logfileActivityCount; logfileActivityCount = 0; return logfileLines; } /** Obtains a lock on the logging mutex. */ int lockLoggingMutex() { #ifdef WIN32 switch (WaitForSingleObject(log_printfMutexHandle, INFINITE)) { case WAIT_ABANDONED: _tprintf(TEXT("Logging mutex was abandoned.\n")); return -1; case WAIT_FAILED: _tprintf(TEXT("Logging mutex wait failed.\n")); return -1; case WAIT_TIMEOUT: _tprintf(TEXT("Logging mutex wait timed out.\n")); return -1; default: /* Ok */ break; } #else if (pthread_mutex_lock(&log_printfMutex)) { _tprintf(TEXT("Failed to lock the Logging mutex. %s\n"), getLastErrorText()); return -1; } #endif return 0; } /** Releases a lock on the logging mutex. */ int releaseLoggingMutex() { #ifdef WIN32 if (!ReleaseMutex(log_printfMutexHandle)) { _tprintf( TEXT("Failed to release logging mutex. %s\n"), getLastErrorText()); return -1; } #else if (pthread_mutex_unlock(&log_printfMutex)) { _tprintf(TEXT("Failed to unlock the Logging mutex. %s\n"), getLastErrorText()); return -1; } #endif return 0; } /** Sets the auto flush log file flag. */ void setLogfileAutoFlush(int autoFlush) { autoFlushLogfile = autoFlush; } /** Sets the auto close log file flag. */ void setLogfileAutoClose(int autoClose) { autoCloseLogfile = autoClose; } /** Closes the logfile if it is open. */ void closeLogfile() { /* We need to be very careful that only one thread is allowed in here * at a time. On Windows this is done using a Mutex object that is * initialized in the initLogging function. */ if (lockLoggingMutex()) { return; } if (logfileFP != NULL) { #ifdef _DEBUG _tprintf(TEXT("Closing logfile by request...\n")); #endif fclose(logfileFP); logfileFP = NULL; /* Do not clean the currentLogFileName here as the name is not actually changing. */ } /* Release the lock we have on this function so that other threads can get in. */ if (releaseLoggingMutex()) { return; } } /** Flushes any buffered logfile output to the disk. */ void flushLogfile() { /* We need to be very careful that only one thread is allowed in here * at a time. On Windows this is done using a Mutex object that is * initialized in the initLogging function. */ if (lockLoggingMutex()) { return; } if (logfileFP != NULL) { #ifdef _DEBUG _tprintf(TEXT("Flushing logfile by request...\n")); #endif fflush(logfileFP); } /* Release the lock we have on this function so that other threads can get in. */ if (releaseLoggingMutex()) { return; } } /* Console functions */ void setConsoleLogFormat( const TCHAR *console_log_format ) { if ( console_log_format != NULL ) { _tcsncpy( consoleFormat, console_log_format, 32 ); /* We only want to time logging if it is needed. */ if ((logPrintfWarnThreshold <= 0) && (_tcschr(console_log_format, TEXT('G')))) { logPrintfWarnThreshold = 99999999; } } } void setConsoleLogLevelInt( int console_log_level ) { currentConsoleLevel = console_log_level; } int getConsoleLogLevelInt() { return currentConsoleLevel; } void setConsoleLogLevel( const TCHAR *console_log_level ) { setConsoleLogLevelInt(getLogLevelForName(console_log_level)); } void setConsoleFlush( int flush ) { consoleFlush = flush; } #ifdef WIN32 void setConsoleDirect( int direct ) { consoleDirect = direct; } #endif void setConsoleFatalToStdErr(int toStdErr) { consoleFatalToStdErr = toStdErr; } void setConsoleErrorToStdErr(int toStdErr) { consoleErrorToStdErr = toStdErr; } void setConsoleWarnToStdErr(int toStdErr) { consoleWarnToStdErr = toStdErr; } /* Syslog/eventlog functions */ void setSyslogLevelInt( int loginfo_level ) { currentLoginfoLevel = loginfo_level; } int getSyslogLevelInt() { return currentLoginfoLevel; } void setSyslogLevel( const TCHAR *loginfo_level ) { setSyslogLevelInt(getLogLevelForName(loginfo_level)); } void setSyslogSplitMessages(int splitMessages) { currentLogSplitMessages = splitMessages; } #ifndef WIN32 void setSyslogFacilityInt( int logfacility_level ) { currentLogfacilityLevel = logfacility_level; } void setSyslogFacility( const TCHAR *loginfo_level ) { setSyslogFacilityInt(getLogFacilityForName(loginfo_level)); } #endif void setSyslogEventSourceName( const TCHAR *event_source_name ) { size_t size; if (event_source_name != NULL) { if (loginfoSourceName != defaultLoginfoSourceName) { if (loginfoSourceName != NULL) { free(loginfoSourceName); } } #ifdef WIN32 size = sizeof(TCHAR) * (_tcslen(event_source_name) + 1); #else size = wcstombs(NULL, event_source_name, 0); if (size == (size_t)-1) { return; } size++; #endif loginfoSourceName = malloc(size); if (!loginfoSourceName) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("SSESN")); loginfoSourceName = defaultLoginfoSourceName; return; } #ifdef WIN32 _tcsncpy(loginfoSourceName, event_source_name, _tcslen(event_source_name) + 1); if (_tcslen(loginfoSourceName) > 32) { loginfoSourceName[32] = TEXT('\0'); } #else wcstombs(loginfoSourceName, event_source_name, size); if (strlen(loginfoSourceName) > 32) { loginfoSourceName[32] = '\0'; } #endif } } void resetDuration() { #ifdef WIN32 struct _timeb timebNow; #else struct timeval timevalNow; #endif time_t now; int nowMillis; #ifdef WIN32 _ftime(&timebNow); now = (time_t)timebNow.time; nowMillis = timebNow.millitm; #else gettimeofday(&timevalNow, NULL); now = (time_t)timevalNow.tv_sec; nowMillis = timevalNow.tv_usec / 1000; #endif previousNow = now; previousNowMillis = nowMillis; } int getLowLogLevel() { int lowLogLevel = (currentLogfileLevel < currentConsoleLevel ? currentLogfileLevel : currentConsoleLevel); lowLogLevel = (currentLoginfoLevel < lowLogLevel ? currentLoginfoLevel : lowLogLevel); return lowLogLevel; } TCHAR* preparePrintBuffer(size_t reqSize) { if (threadPrintBuffer == NULL) { threadPrintBuffer = malloc(sizeof(TCHAR) * reqSize); if (!threadPrintBuffer) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("PPB1")); threadPrintBufferSize = 0; return NULL; } threadPrintBufferSize = reqSize; } else if (threadPrintBufferSize < reqSize) { free(threadPrintBuffer); threadPrintBuffer = malloc(sizeof(TCHAR) * reqSize); if (!threadPrintBuffer) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("PPB2")); threadPrintBufferSize = 0; return NULL; } threadPrintBufferSize = reqSize; } return threadPrintBuffer; } /* Writes to and then returns a buffer that is reused by the current thread. * It should not be released. */ TCHAR* buildPrintBuffer( int source_id, int level, int threadId, int queued, struct tm *nowTM, int nowMillis, time_t durationMillis, const TCHAR *format, const TCHAR *defaultFormat, const TCHAR *message) { int i; size_t reqSize; int numColumns; TCHAR *pos; int currentColumn; int handledFormat; int temp; int len; /* Decide the number of columns and come up with a required length for the printBuffer. */ reqSize = 0; for( i = 0, numColumns = 0; i < (int)_tcslen( format ); i++ ) { switch( format[i] ) { case TEXT('P'): case TEXT('p'): reqSize += 8 + 3; numColumns++; break; case TEXT('L'): case TEXT('l'): reqSize += 6 + 3; numColumns++; break; case TEXT('D'): case TEXT('d'): reqSize += 7 + 3; numColumns++; break; case TEXT('Q'): case TEXT('q'): reqSize += 1 + 3; numColumns++; break; case TEXT('T'): case TEXT('t'): reqSize += 19 + 3; numColumns++; break; case TEXT('Z'): case TEXT('z'): reqSize += 23 + 3; numColumns++; break; case TEXT('U'): case TEXT('u'): reqSize += 8 + 3; numColumns++; break; case TEXT('R'): case TEXT('r'): reqSize += 8 + 3; numColumns++; break; case TEXT('G'): case TEXT('g'): reqSize += 10 + 3; numColumns++; break; case TEXT('M'): case TEXT('m'): reqSize += _tcslen( message ) + 3; numColumns++; break; } } if ((reqSize == 0) && (defaultFormat != NULL)) { /* This means that the specified format was completely invalid. * Recurse using the defaultFormat instead. * The alternative would be to log an empty line, which is useless to everyone. */ return buildPrintBuffer( source_id, level, threadId, queued, nowTM, nowMillis, durationMillis, defaultFormat, NULL /* No default. Prevent further recursion. */, message ); } /* Always add room for the null. */ reqSize += 1; if ( !preparePrintBuffer(reqSize)) { return NULL; } /* Always start with a null terminated string in case there are no formats specified. */ threadPrintBuffer[0] = TEXT('\0'); /* Create a pointer to the beginning of the print buffer, it will be advanced * as the formatted message is build up. */ pos = threadPrintBuffer; /* We now have a buffer large enough to store the entire formatted message. */ for( i = 0, currentColumn = 0, len = 0, temp = 0; i < (int)_tcslen( format ); i++ ) { handledFormat = TRUE; switch( format[i] ) { case TEXT('P'): case TEXT('p'): switch ( source_id ) { case WRAPPER_SOURCE_WRAPPER: #ifdef WIN32 if (launcherSource) { temp = _sntprintf( pos, reqSize - len, TEXT("wrapperm") ); } else { temp = _sntprintf( pos, reqSize - len, TEXT("wrapper ") ); } #else temp = _sntprintf( pos, reqSize - len, TEXT("wrapper ") ); #endif break; case WRAPPER_SOURCE_PROTOCOL: temp = _sntprintf( pos, reqSize - len, TEXT("wrapperp") ); break; default: temp = _sntprintf( pos, reqSize - len, TEXT("jvm %-4d"), source_id ); break; } currentColumn++; break; case TEXT('L'): case TEXT('l'): temp = _sntprintf( pos, reqSize - len, TEXT("%s"), logLevelNames[ level ] ); currentColumn++; break; case TEXT('D'): case TEXT('d'): switch ( threadId ) { case WRAPPER_THREAD_SIGNAL: temp = _sntprintf( pos, reqSize - len, TEXT("signal ") ); break; case WRAPPER_THREAD_MAIN: temp = _sntprintf( pos, reqSize - len, TEXT("main ") ); break; case WRAPPER_THREAD_SRVMAIN: temp = _sntprintf( pos, reqSize - len, TEXT("srvmain") ); break; case WRAPPER_THREAD_TIMER: temp = _sntprintf( pos, reqSize - len, TEXT("timer ") ); break; case WRAPPER_THREAD_JAVAIO: temp = _sntprintf( pos, reqSize - len, TEXT("javaio ") ); break; case WRAPPER_THREAD_STARTUP: temp = _sntprintf( pos, reqSize - len, TEXT("startup") ); break; default: temp = _sntprintf( pos, reqSize - len, TEXT("unknown") ); break; } currentColumn++; break; case TEXT('Q'): case TEXT('q'): temp = _sntprintf( pos, reqSize - len, TEXT("%c"), ( queued ? TEXT('Q') : TEXT(' '))); currentColumn++; break; case TEXT('T'): case TEXT('t'): temp = _sntprintf( pos, reqSize - len, TEXT("%04d/%02d/%02d %02d:%02d:%02d"), nowTM->tm_year + 1900, nowTM->tm_mon + 1, nowTM->tm_mday, nowTM->tm_hour, nowTM->tm_min, nowTM->tm_sec ); currentColumn++; break; case TEXT('Z'): case TEXT('z'): temp = _sntprintf( pos, reqSize - len, TEXT("%04d/%02d/%02d %02d:%02d:%02d.%03d"), nowTM->tm_year + 1900, nowTM->tm_mon + 1, nowTM->tm_mday, nowTM->tm_hour, nowTM->tm_min, nowTM->tm_sec, nowMillis ); currentColumn++; break; case TEXT('U'): case TEXT('u'): if (uptimeFlipped) { temp = _sntprintf( pos, reqSize - len, TEXT("--------") ); } else { temp = _sntprintf( pos, reqSize - len, TEXT("%8d"), uptimeSeconds); } currentColumn++; break; case TEXT('R'): case TEXT('r'): if (durationMillis == (time_t)-1) { temp = _sntprintf( pos, reqSize - len, TEXT(" ") ); } else if (durationMillis > 99999999) { temp = _sntprintf( pos, reqSize - len, TEXT("99999999") ); } else { temp = _sntprintf( pos, reqSize - len, TEXT("%8d"), durationMillis); } currentColumn++; break; case TEXT('G'): case TEXT('g'): temp = _sntprintf( pos, reqSize - len, TEXT("%8d"), __min(previousLogLag, 99999999)); currentColumn++; break; case TEXT('M'): case TEXT('m'): temp = _sntprintf( pos, reqSize - len, TEXT("%s"), message ); currentColumn++; break; default: handledFormat = FALSE; } if (handledFormat) { pos += temp; len += temp; /* Add separator chars */ if (currentColumn != numColumns) { temp = _sntprintf(pos, reqSize - len, TEXT(" | ")); pos += temp; len += temp; } } } /* Return the print buffer to the caller. */ return threadPrintBuffer; } /** * Generates a log file name given. * * buffer - Buffer into which to _sntprintf the generated name. * bufferSize - Size of the buffer. * template - Template from which the name is generated. * nowDate - Optional date used to replace any YYYYMMDD tokens. * rollNum - Optional roll number used to replace any ROLLNUM tokens. */ void generateLogFileName(TCHAR *buffer, size_t bufferSize, const TCHAR *template, const TCHAR *nowDate, const TCHAR *rollNum ) { size_t bufferLen; /* Copy the template to the buffer to get started. */ _tcsncpy(buffer, template, _tcslen(logFilePath) + 11); /* Handle the date token. */ if (_tcsstr(buffer, TEXT("YYYYMMDD"))) { if (nowDate == NULL) { /* The token needs to be removed. */ replaceStringLongWithShort(buffer, TEXT("-YYYYMMDD"), NULL); replaceStringLongWithShort(buffer, TEXT("_YYYYMMDD"), NULL); replaceStringLongWithShort(buffer, TEXT(".YYYYMMDD"), NULL); replaceStringLongWithShort(buffer, TEXT("YYYYMMDD"), NULL); } else { /* The token needs to be replaced. */ replaceStringLongWithShort(buffer, TEXT("YYYYMMDD"), nowDate); } } /* Handle the roll number token. */ if (_tcsstr(buffer, TEXT("ROLLNUM"))) { if (rollNum == NULL ) { /* The token needs to be removed. */ replaceStringLongWithShort(buffer, TEXT("-ROLLNUM"), NULL); replaceStringLongWithShort(buffer, TEXT("_ROLLNUM"), NULL); replaceStringLongWithShort(buffer, TEXT(".ROLLNUM"), NULL); replaceStringLongWithShort(buffer, TEXT("ROLLNUM"), NULL); } else { /* The token needs to be replaced. */ replaceStringLongWithShort(buffer, TEXT("ROLLNUM"), rollNum); } } else { /* The name did not contain a ROLLNUM token. */ if (rollNum != NULL ) { /* Generate the name as if ".ROLLNUM" was appended to the template. */ bufferLen = _tcslen(buffer); _sntprintf(buffer + bufferLen, bufferSize - bufferLen, TEXT(".%s"), rollNum); buffer[bufferSize - 1] = TEXT('\0'); } } } /** * Prints the contents of a buffer to the sysLog target. The log level is * tested prior to this function being called. * * Must be called while locked. */ void log_printf_message_sysLogInner(int source_id, int level, TCHAR *message, struct tm *nowTM) { #ifdef WIN32 sendEventlogMessage(source_id, level, message); #else sendLoginfoMessage(source_id, level, message); #endif } /** * @param invertLogLevelCheck There is a special case where we want to log to * the syslog IF and only if the normal log output * would not go to the syslog. This flag makes it * possible to log if it we normally would not. */ void log_printf_message_sysLog(int source_id, int level, TCHAR *message, struct tm *nowTM, int invertLogLevelCheck) { switch (level) { case LEVEL_NOTICE: case LEVEL_ADVICE: /* Advice and Notice level messages are special in that they never get logged to the * EventLog / SysLog. */ break; default: if (invertLogLevelCheck) { /* Log if we normally should not log. */ if (level < currentLoginfoLevel) { log_printf_message_sysLogInner(source_id, level, message, nowTM); } } else { if (level >= currentLoginfoLevel) { log_printf_message_sysLogInner(source_id, level, message, nowTM); } } } } /** * Prints the contents of a buffer to the logfile target. The log level is * tested prior to this function being called. * * Must be called while locked. * * @return True if the logfile name changed. */ int log_printf_message_logFileInner(int source_id, int level, int threadId, int queued, TCHAR *message, struct tm *nowTM, int nowMillis, time_t durationMillis) { int logFileChanged = FALSE; TCHAR nowDate[9]; TCHAR *printBuffer; int old_umask; const TCHAR *tempBufferFormat; const TCHAR *tempBufferLastErrorText; size_t tempBufferLen; TCHAR *tempBuffer; /* If the log file was set to a blank value then it will not be used. */ if (logFilePath && (_tcslen(logFilePath) > 0)) { /* If this the roll mode is date then we need a nowDate for this log entry. */ if (logFileRollMode & ROLL_MODE_DATE) { _sntprintf(nowDate, 9, TEXT("%04d%02d%02d"), nowTM->tm_year + 1900, nowTM->tm_mon + 1, nowTM->tm_mday ); } else { nowDate[0] = TEXT('\0'); } /* Make sure that the log file does not need to be rolled. */ checkAndRollLogs(nowDate); /* If the file needs to be opened then do so. */ if (logfileFP == NULL) { /* Generate the log file name if it is not already set. */ if (currentLogFileName[0] == TEXT('\0')) { if (logFileRollMode & ROLL_MODE_DATE) { generateLogFileName(currentLogFileName, currentLogFileNameSize, logFilePath, nowDate, NULL); } else { generateLogFileName(currentLogFileName, currentLogFileNameSize, logFilePath, NULL, NULL); } logFileChanged = TRUE; } old_umask = umask( logFileUmask ); logfileFP = _tfopen(currentLogFileName, TEXT("a")); if (logfileFP == NULL) { /* The log file could not be opened. */ /* We need to write our error message into a buffer manually so we can use it * both for the log_printf_queue and log_printf_message_sysLog calls below. */ tempBufferFormat = TEXT("Unable to write to the configured log file: %s (%s)\n Falling back to the default file in the current working directory: %s"); tempBufferLastErrorText = getLastErrorText(); tempBufferLen = _tcslen(tempBufferFormat) - 2 - 2 - 2 + _tcslen(currentLogFileName) + _tcslen(tempBufferLastErrorText) + _tcslen(defaultLogFile) + 1; tempBuffer = malloc(sizeof(TCHAR) * tempBufferLen); if (!tempBuffer) { outOfMemoryQueued(TEXT("LPML"), 1 ); } else { _sntprintf(tempBuffer, tempBufferLen, tempBufferFormat, currentLogFileName, getLastErrorText(), defaultLogFile); log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s"), tempBuffer); /* This is critical for debugging problems. If the above message would not have shown * up in the syslog then send it there manually. We are already locked here so this * can be done safely. */ log_printf_message_sysLog(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, tempBuffer, nowTM, TRUE); free(tempBuffer); } /* Try the default file location. */ setLogfilePath(defaultLogFile, NULL, TRUE); _sntprintf(currentLogFileName, currentLogFileNameSize, defaultLogFile); logFileChanged = TRUE; logfileFP = _tfopen(currentLogFileName, TEXT("a")); if (logfileFP == NULL) { /* Still unable to write. */ /* We need to write our error message into a buffer manually so we can use it * both for the log_printf_queue and log_printf_message_sysLog calls below. */ tempBufferFormat = TEXT("Unable to write to the default log file: %s (%s)\n Disabling log file."); tempBufferLastErrorText = getLastErrorText(); tempBufferLen = _tcslen(tempBufferFormat) - 2 - 2 + _tcslen(currentLogFileName) + _tcslen(tempBufferLastErrorText) + 1; tempBuffer = malloc(sizeof(TCHAR) * tempBufferLen); if (!tempBuffer) { outOfMemoryQueued(TEXT("LPML"), 1 ); } else { _sntprintf(tempBuffer, tempBufferLen, tempBufferFormat, currentLogFileName, getLastErrorText()); log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s"), tempBuffer); /* This is critical for debugging problems. If the above message would not have shown * up in the syslog then send it there manually. We are already locked here so this * can be done safely. */ log_printf_message_sysLog(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, tempBuffer, nowTM, TRUE); free(tempBuffer); } setLogfileLevelInt(LEVEL_NONE); logFileChanged = FALSE; } } umask(old_umask); #ifdef _DEBUG if (logfileFP != NULL) { _tprintf(TEXT("Opened logfile\n")); } #endif } if (logfileFP == NULL) { currentLogFileName[0] = TEXT('\0'); /* Failure to write to logfile already reported. */ } else { /* We need to store the date the file was opened for. */ _tcsncpy(logFileLastNowDate, nowDate, 9); /* Build up the printBuffer. */ printBuffer = buildPrintBuffer(source_id, level, threadId, queued, nowTM, nowMillis, durationMillis, logfileFormat, LOG_FORMAT_LOGFILE_DEFAULT, message); if (printBuffer) { _ftprintf(logfileFP, TEXT("%s\n"), printBuffer); logFileAccessed = TRUE; /* Increment the activity counter. */ logfileActivityCount++; /* Decide whether we want to close or flush the log file immediately after each line. * If not then flushing and closing will be handled externally by calling flushLogfile() or closeLogfile(). */ if (autoCloseLogfile) { /* Close the log file immediately. */ #ifdef _DEBUG _tprintf(TEXT("Closing logfile immediately...\n")); #endif fclose(logfileFP); logfileFP = NULL; /* Do not clear the currentLogFileName here as we are not changing its name. */ } else if (autoFlushLogfile) { /* Flush the log file immediately. */ #ifdef _DEBUG _tprintf(TEXT("Flushing logfile immediately...\n")); #endif fflush(logfileFP); } /* Leave the file open. It will be closed later after a period of inactivity. */ } } } return logFileChanged; } int log_printf_message_logFile(int source_id, int level, int threadId, int queued, TCHAR *message, struct tm *nowTM, int nowMillis, time_t durationMillis) { int logFileChanged = FALSE; if (level >= currentLogfileLevel) { logFileChanged = log_printf_message_logFileInner(source_id, level, threadId, queued, message, nowTM, nowMillis, durationMillis); } return logFileChanged; } /** * Prints the contents of a buffer to the console target. The log level is * tested prior to this function being called. * * Must be called while locked. */ void log_printf_message_consoleInner(int source_id, int level, int threadId, int queued, TCHAR *message, struct tm *nowTM, int nowMillis, time_t durationMillis) { TCHAR *printBuffer; FILE *target; #ifdef WIN32 HANDLE targetH; int complete = FALSE; #endif /* Build up the printBuffer. */ printBuffer = buildPrintBuffer(source_id, level, threadId, queued, nowTM, nowMillis, durationMillis, consoleFormat, LOG_FORMAT_CONSOLE_DEFAULT, message); if (printBuffer) { /* Decide where to send the output. */ switch (level) { case LEVEL_FATAL: if (consoleFatalToStdErr) { target = stderr; } else { target = stdout; } break; case LEVEL_ERROR: if (consoleErrorToStdErr) { target = stderr; } else { target = stdout; } break; case LEVEL_WARN: if (consoleWarnToStdErr) { target = stderr; } else { target = stdout; } break; default: target = stdout; break; } /* Write the print buffer to the console. */ #ifdef WIN32 /* Using the WinAPI function WriteConsole would make it impossible to pipe the console output. * We never want to allow direct console writing if this is a launcher instance.*/ if (consoleDirect) { if (target == stderr) { targetH = GetStdHandle(STD_ERROR_HANDLE); } else { targetH = GetStdHandle(STD_OUTPUT_HANDLE); } if (targetH != NULL) { complete = writeToConsole(targetH, TEXT("%s\n"), printBuffer); } else { /* Should not happen. But just in case. */ _tprintf(TEXT("Failed to find standard handle. Disabled direct console output.\n")); consoleDirect = FALSE; } } if (!complete) { #endif _ftprintf(target, TEXT("%s\n"), printBuffer); if (consoleFlush) { fflush(target); } #ifdef WIN32 } #endif } } void log_printf_message_console(int source_id, int level, int threadId, int queued, TCHAR *message, struct tm *nowTM, int nowMillis, time_t durationMillis) { if (level >= currentConsoleLevel) { log_printf_message_consoleInner(source_id, level, threadId, queued, message, nowTM, nowMillis, durationMillis); } } /** * Prints the contents of a buffer to all configured targets. * * Must be called while locked. * * @param sysLogEnabled A flag that is used to help with recursion to control * whether or not the syslog should be considered as a log * target for this call. It is always disabled when we * recurse. * * @return True if the logfile name changed. */ int log_printf_message(int source_id, int level, int threadId, int queued, TCHAR *message, int sysLogEnabled) { #ifndef WIN32 TCHAR *printBuffer; FILE *target; #endif int logFileChanged = FALSE; TCHAR *subMessage; TCHAR *nextLF; #ifdef WIN32 struct _timeb timebNow; #else size_t reqSize; struct timeval timevalNow; TCHAR intBuffer[3]; TCHAR* pos; #endif time_t now; int nowMillis; struct tm *nowTM; time_t durationMillis; #ifndef WIN32 if ((_tcsstr(message, LOG_SPECIAL_MARKER) == message) && (_tcslen(message) >= _tcslen(LOG_SPECIAL_MARKER) + 10)) { /* Got a special encoded log message from the child Wrapper process. * Parse it and continue as if the log message came from this process. * These should never be multi-line messages as the forked child * process will have already broken them up. */ pos = (TCHAR *)(message + _tcslen(LOG_SPECIAL_MARKER) + 1); /* source_id */ _tcsncpy(intBuffer, pos, 2); intBuffer[2] = TEXT('\0'); source_id = _ttoi(intBuffer); pos += 3; /* level */ _tcsncpy(intBuffer, pos, 2); intBuffer[2] = TEXT('\0'); level = _ttoi(intBuffer); pos += 3; /* threadId */ _tcsncpy(intBuffer, pos, 2); intBuffer[2] = TEXT('\0'); threadId = _ttoi(intBuffer); pos += 3; /* message */ message = pos; } #endif /* Build a timestamp */ #ifdef WIN32 _ftime( &timebNow ); now = (time_t)timebNow.time; nowMillis = timebNow.millitm; #else gettimeofday( &timevalNow, NULL ); now = (time_t)timevalNow.tv_sec; nowMillis = timevalNow.tv_usec / 1000; #endif nowTM = localtime( &now ); /* Calculate the number of milliseconds which have passed since the previous log entry. * We only need to display up to 8 digits, so if the result is going to be larger than * that, set it to 100000000. * We only want to do this for output coming from the JVM. Any other log output should * be set to (time_t)-1. */ switch(source_id) { case WRAPPER_SOURCE_WRAPPER: case WRAPPER_SOURCE_PROTOCOL: durationMillis = (time_t)-1; break; default: if (now - previousNow > 100000) { /* Without looking at the millis, we know it is already too long. */ durationMillis = 100000000; } else { durationMillis = (now - previousNow) * 1000 + nowMillis - previousNowMillis; } previousNow = now; previousNowMillis = nowMillis; break; } if (!currentLogSplitMessages) { /* Syslog messages are printed first so we can print them including line feeds as is. * This must be done before we break up multi-line messages into individual lines. */ #ifdef WIN32 if (sysLogEnabled) { #else /* On UNIX we never want to log to the syslog here if this is in a forked thread. * In this case, any lines will be broken up into individual lines and then logged * as usual by the main process. But this can't be helped and is very rare anyway. */ if (sysLogEnabled && (_tcsstr(message, LOG_FORK_MARKER) != message)) { #endif /* syslog/Eventlog. */ log_printf_message_sysLog(source_id, level, message, nowTM, FALSE); } } /* If the message contains line feeds then break up the line into substrings and recurse. */ subMessage = message; nextLF = _tcschr(subMessage, TEXT('\n')); if (nextLF) { /* This string contains more than one line. Loop over the strings. It is Ok to corrupt this string because it is only used once. */ while (nextLF) { nextLF[0] = TEXT('\0'); logFileChanged |= log_printf_message(source_id, level, threadId, queued, subMessage, FALSE); /* Locate the next one. */ subMessage = &(nextLF[1]); nextLF = _tcschr(subMessage, TEXT('\n')); } /* The rest of the buffer will be the final line. */ logFileChanged |= log_printf_message(source_id, level, threadId, queued, subMessage, FALSE); return logFileChanged; } #ifndef WIN32 /* See if this is a special case log entry from the forked child. */ if (_tcsstr(message, LOG_FORK_MARKER) == message) { /* Found the marker. We only want to log the message as is to the console with a special prefix. * This is used to pass the log output through the pipe to the parent Wrapper process where it * will be decoded below and displayed appropriately. */ reqSize = _tcslen(LOG_SPECIAL_MARKER) + 1 + 2 + 1 + 2 + 1 + 2 + 1 + _tcslen(message) - _tcslen(LOG_FORK_MARKER) + 1; if (!(printBuffer = preparePrintBuffer(reqSize))) { return FALSE; } _sntprintf(printBuffer, reqSize, TEXT("%s|%02d|%02d|%02d|%s"), LOG_SPECIAL_MARKER, source_id, level, threadId, message + _tcslen(LOG_FORK_MARKER)); /* Decide where to send the output. */ switch (level) { case LEVEL_FATAL: if (consoleFatalToStdErr) { target = stderr; } else { target = stdout; } break; case LEVEL_ERROR: if (consoleErrorToStdErr) { target = stderr; } else { target = stdout; } break; case LEVEL_WARN: if (consoleWarnToStdErr) { target = stderr; } else { target = stdout; } break; default: target = stdout; break; } _ftprintf(target, TEXT("%s\n"), printBuffer); if (consoleFlush) { fflush(target); } return FALSE; } #endif /* Get the current threadId. */ if ( threadId < 0 ) { /* The current thread was specified. Resolve what thread this actually is. */ threadId = getThreadId(); } /* Syslog outbut by format (If messages splitting is enabled. Otherwise done above.) */ if (currentLogSplitMessages) { log_printf_message_sysLog(source_id, level, message, nowTM, FALSE); } /* Console output by format */ log_printf_message_console(source_id, level, threadId, queued, message, nowTM, nowMillis, durationMillis); /* Logfile output by format */ logFileChanged = log_printf_message_logFile(source_id, level, threadId, queued, message, nowTM, nowMillis, durationMillis); return logFileChanged; } /** * Used for testing to pause the current thread for the specified number of seconds. * This can only be called when logging is locked. * * @param pauseTime Number of seconds to pause, 0 pauses indefinitely. */ void pauseThread(int pauseTime) { int i; if (pauseTime > 0) { for (i = 0; i < pauseTime; i++) { logSleep(1000); } } else { while (TRUE) { logSleep(1000); } } } /* General log functions */ void log_printf( int source_id, int level, const TCHAR *lpszFmt, ... ) { va_list vargs; int count; int threadId; int logFileChanged; TCHAR *logFileCopy; #if defined(UNICODE) && !defined(WIN32) TCHAR *msg = NULL; int i; int flag; #endif #ifdef WIN32 struct _timeb timebNow; #else struct timeval timevalNow; #endif time_t startNow; int startNowMillis; time_t endNow; int endNowMillis; if (level == LEVEL_NONE) { /* Some APIs allow the user to potentially configure the NONE log level. Skip it as it means no logging in this case. */ return; } /* If we are checking on the log time then store the start time. */ if (logPrintfWarnThreshold > 0) { #ifdef WIN32 _ftime(&timebNow); startNow = (time_t)timebNow.time; startNowMillis = timebNow.millitm; #else gettimeofday(&timevalNow, NULL); startNow = (time_t)timevalNow.tv_sec; startNowMillis = timevalNow.tv_usec / 1000; #endif } else { startNow = 0; startNowMillis = 0; } /* We need to be very careful that only one thread is allowed in here * at a time. On Windows this is done using a Mutex object that is * initialized in the initLogging function. */ if (lockLoggingMutex()) { return; } /* If there is a queued pause then do so. */ if ((logPauseTime >= 0) && (level > LEVEL_DEBUG) && (source_id < 0)) { pauseThread(logPauseTime); logPauseTime = -1; } #if defined(UNICODE) && !defined(WIN32) if (source_id < 1 && wcsstr(lpszFmt, TEXT("%s")) != NULL) { msg = malloc(sizeof(wchar_t) * (wcslen(lpszFmt) + 1)); if (msg) { /* Loop over the format and convert all '%s' patterns to %S' so the UNICODE displays correctly. */ if (wcslen(lpszFmt) > 0) { for (i = 0; i < _tcslen(lpszFmt); i++){ msg[i] = lpszFmt[i]; if ((lpszFmt[i] == TEXT('%')) && (i < _tcslen(lpszFmt)) && (lpszFmt[i + 1] == TEXT('s')) && ((i == 0) || (lpszFmt[i - 1] != TEXT('%')))){ msg[i+1] = TEXT('S'); i++; } } } msg[wcslen(lpszFmt)] = TEXT('\0'); } else { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("P1")); return; } flag = TRUE; } else { msg = (TCHAR*) lpszFmt; flag = FALSE; } #endif threadId = getThreadId(); if (source_id <= 0) { /* Loop until the buffer is large enough that we are able to successfully * print into it. Once the buffer has grown to the largest message size, * smaller messages will pass through this code without looping. */ do { if ( threadMessageBufferSize == 0 ) { /* No buffer yet. Allocate one to get started. */ threadMessageBufferSize = 100; #if defined(HPUX) /* Due to a bug in the HPUX libc (version < 1403), the length of the buffer passed to _vsntprintf must have a length of 1 + N, where N is a multiple of 8. Adjust it as necessary. */ threadMessageBufferSize = threadMessageBufferSize + (((threadMessageBufferSize - 1) % 8) == 0 ? 0 : 8 - ((threadMessageBufferSize - 1) % 8)); #endif threadMessageBuffer = malloc(sizeof(TCHAR) * threadMessageBufferSize); if (!threadMessageBuffer) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("P2")); threadMessageBufferSize = 0; #if defined(UNICODE) && !defined(WIN32) if (flag == TRUE) { free(msg); } #endif return; } } /* Try writing to the buffer. */ va_start( vargs, lpszFmt ); #if defined(UNICODE) && !defined(WIN32) count = _vsntprintf( threadMessageBuffer, threadMessageBufferSize, msg, vargs ); #else count = _vsntprintf( threadMessageBuffer, threadMessageBufferSize, lpszFmt, vargs ); #endif va_end( vargs ); /* _tprintf(TEXT(" vsnprintf->%d, size=%d\n"), count, threadMessageBufferSize ); */ if ( ( count < 0 ) || ( count >= (int)threadMessageBufferSize ) ) { /* If the count is exactly equal to the buffer size then a null TCHAR was not written. * It must be larger. * Windows will return -1 if the buffer is too small. If the number is * exact however, we still need to expand it to have room for the null. * UNIX will return the required size. */ /* Free the old buffer for starters. */ free( threadMessageBuffer ); /* Decide on a new buffer size. * We can't tell how long the resulting string will be without expanding because the * results are stored in the vargs. * Most messages will be short, but there is a possibility that some will be very * long. To minimize the number of times that we need to loop, while at the same * time trying to avoid using too much memory, increase the size by the maximum of * 1024 or 10% of the current length. * Some platforms will return the required size as count. Use that if available. */ threadMessageBufferSize = __max(threadMessageBufferSize + 1024, __max(threadMessageBufferSize + threadMessageBufferSize / 10, (size_t)count + 1)); #if defined(HPUX) /* Due to a bug in the HPUX libc (version < 1403), the length of the buffer passed to _vsntprintf must have a length of 1 + N, where N is a multiple of 8. Adjust it as necessary. */ threadMessageBufferSize = threadMessageBufferSize + (((threadMessageBufferSize - 1) % 8) == 0 ? 0 : 8 - ((threadMessageBufferSize - 1) % 8)); #endif threadMessageBuffer = malloc(sizeof(TCHAR) * threadMessageBufferSize); if (!threadMessageBuffer) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("P3")); threadMessageBufferSize = 0; #if defined(UNICODE) && !defined(WIN32) if (flag == TRUE) { free(msg); } #endif return; } /* Always set the count to -1 so we will loop again. */ count = -1; } } while ( count < 0 ); } #if defined(UNICODE) && !defined(WIN32) if (flag == TRUE) { free(msg); } #endif logFileCopy = NULL; if (source_id > 0) { #if defined(UNICODE) && !defined(WIN32) logFileChanged = log_printf_message(source_id, level, threadId, FALSE, msg, TRUE); #else logFileChanged = log_printf_message(source_id, level, threadId, FALSE, (TCHAR*) lpszFmt, TRUE); #endif } else { logFileChanged = log_printf_message(source_id, level, threadId, FALSE, threadMessageBuffer, TRUE); } if (logFileChanged) { /* We need to enqueue a notification that the log file name was changed. * We can NOT directly send the notification here as that could cause a deadlock, * depending on where exactly this function was called from. (See Wrapper protocol mutex.) */ logFileCopy = malloc(sizeof(TCHAR) * (_tcslen(currentLogFileName) + 1)); if (!logFileCopy) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("P4")); } else { _tcsncpy(logFileCopy, currentLogFileName, _tcslen(currentLogFileName) + 1); /* Now after we have 100% prepared the log file name. Put into the queue variable * so the maintainLogging() function can safely grab it at any time. * The reading code is also in a semaphore so we can do a quick test here safely as well. */ if (pendingLogFileChange) { /* The previous file was still in the queue. Free it up to avoid a memory leak. * This can happen if the log file size is 1k or something like that. We will always * keep the most recent file however, so this should not be that big a problem. */ #ifdef _DEBUG _tprintf(TEXT("Log file name change was overwritten in queue: %s\n"), pendingLogFileChange); #endif free(pendingLogFileChange); } pendingLogFileChange = logFileCopy; } } /* Release the lock we have on this function so that other threads can get in. */ if (releaseLoggingMutex()) { return; } /* If we are checking on the log time then store the stop time. * It is Ok that some of the error paths don't make it this far. */ if (logPrintfWarnThreshold > 0) { #ifdef WIN32 _ftime(&timebNow); endNow = (time_t)timebNow.time; endNowMillis = timebNow.millitm; #else gettimeofday(&timevalNow, NULL); endNow = (time_t)timevalNow.tv_sec; endNowMillis = timevalNow.tv_usec / 1000; #endif previousLogLag = __min(endNow - startNow, 3600) * 1000 + endNowMillis - startNowMillis; if (previousLogLag >= logPrintfWarnThreshold) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Write to log took %d milliseconds."), previousLogLag); } } } /* Internal functions */ #define LAST_ERROR_TEXT_BUFFER_SIZE 1024 /** Buffer holding the last error message. * TODO: This needs to be made thread safe, meaning that we need a buffer for each thread. */ TCHAR lastErrorTextBufferW[LAST_ERROR_TEXT_BUFFER_SIZE]; /** * Returns a textual error message of the last error encountered. * * @return The last error message. */ const TCHAR* getLastErrorText() { int errorNum; #ifdef WIN32 DWORD dwRet; TCHAR* lpszTemp = NULL; #else char* lastErrorTextMB; size_t req; #endif #ifdef WIN32 errorNum = GetLastError(); dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), LANG_NEUTRAL, (TCHAR*)&lpszTemp, 0, NULL); /* supplied buffer is not long enough */ if ((!dwRet) || ((long)LAST_ERROR_TEXT_BUFFER_SIZE - 1 < (long)dwRet + 14)) { _sntprintf(lastErrorTextBufferW, LAST_ERROR_TEXT_BUFFER_SIZE, TEXT("Error Message too large (Size %d) (Error 0x%x)"), dwRet, errorNum); } else { lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); /*remove cr and newline character */ _sntprintf(lastErrorTextBufferW, LAST_ERROR_TEXT_BUFFER_SIZE, TEXT("%s (0x%x)"), lpszTemp, errorNum); } /* following the documentation of FormatMessage, LocalFree should be called to free the output buffer. */ if (lpszTemp) { LocalFree(lpszTemp); } #else errorNum = errno; lastErrorTextMB = strerror(errorNum); req = mbstowcs(NULL, lastErrorTextMB, MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { invalidMultiByteSequence(TEXT("GLET"), 1); _sntprintf(lastErrorTextBufferW, LAST_ERROR_TEXT_BUFFER_SIZE, TEXT("Error Message could not be decoded (Error 0x%x)"), errorNum); } else if (req >= LAST_ERROR_TEXT_BUFFER_SIZE) { _sntprintf(lastErrorTextBufferW, LAST_ERROR_TEXT_BUFFER_SIZE, TEXT("Error Message too large (Size %d) (Error 0x%x)"), req, errorNum); } else { mbstowcs(lastErrorTextBufferW, lastErrorTextMB, LAST_ERROR_TEXT_BUFFER_SIZE); } #endif /* Always reterminate the buffer just to be sure it is safe because badly encoded characters can cause issues. */ lastErrorTextBufferW[LAST_ERROR_TEXT_BUFFER_SIZE - 1] = TEXT('\0'); return lastErrorTextBufferW; } /** * Returns the last error number. * * @return The last error number. */ int getLastError() { #ifdef WIN32 return GetLastError(); #else return errno; #endif } int registerSyslogMessageFile( ) { #ifdef WIN32 TCHAR buffer[_MAX_PATH]; DWORD usedLen; TCHAR regPath[1024]; HKEY hKey; DWORD categoryCount, typesSupported; /* Get absolute path to service manager */ usedLen = GetModuleFileName(NULL, buffer, _MAX_PATH); if (usedLen == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to obtain the full path to the Wrapper. %s"), getLastErrorText()); return -1; } else if ((usedLen == _MAX_PATH) || (getLastError() == ERROR_INSUFFICIENT_BUFFER)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to obtain the full path to the Wrapper. %s"), TEXT("Path to Wrapper binary too long.")); return -1; } else { _sntprintf( regPath, 1024, TEXT("SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\%s"), loginfoSourceName ); if( RegCreateKey( HKEY_LOCAL_MACHINE, regPath, (PHKEY) &hKey ) == ERROR_SUCCESS ) { RegCloseKey( hKey ); if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, regPath, 0, KEY_WRITE, (PHKEY) &hKey ) == ERROR_SUCCESS ) { /* Set EventMessageFile */ if( RegSetValueEx( hKey, TEXT("EventMessageFile"), (DWORD) 0, (DWORD) REG_SZ, (LPBYTE) buffer, (DWORD)(sizeof(TCHAR) * (_tcslen(buffer) + 1))) != ERROR_SUCCESS ) { RegCloseKey( hKey ); return -1; } /* Set CategoryMessageFile */ if( RegSetValueEx( hKey, TEXT("CategoryMessageFile"), (DWORD) 0, (DWORD) REG_SZ, (LPBYTE) buffer, (DWORD)(sizeof(TCHAR) * (_tcslen(buffer) + 1))) != ERROR_SUCCESS ) { RegCloseKey( hKey ); return -1; } /* Set CategoryCount */ categoryCount = 12; if( RegSetValueEx( hKey, TEXT("CategoryCount"), (DWORD) 0, (DWORD) REG_DWORD, (LPBYTE) &categoryCount, sizeof(DWORD) ) != ERROR_SUCCESS ) { RegCloseKey( hKey ); return -1; } /* Set TypesSupported */ typesSupported = 7; if( RegSetValueEx( hKey, TEXT("TypesSupported"), (DWORD) 0, (DWORD) REG_DWORD, (LPBYTE) &typesSupported, sizeof(DWORD) ) != ERROR_SUCCESS ) { RegCloseKey( hKey ); return -1; } RegCloseKey( hKey ); return 0; } } } return -1; /* Failure */ #else return 0; #endif } int unregisterSyslogMessageFile( ) { #ifdef WIN32 /* If we deregister this application, then the event viewer will not work when the program is not running. */ /* Don't want to clutter up the Registry, but is there another way? */ TCHAR regPath[ 1024 ]; /* Get absolute path to service manager */ _sntprintf( regPath, 1024, TEXT("SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\%s"), loginfoSourceName ); if( RegDeleteKey( HKEY_LOCAL_MACHINE, regPath ) == ERROR_SUCCESS ) return 0; return -1; /* Failure */ #else return 0; #endif } #ifdef WIN32 void sendEventlogMessage( int source_id, int level, const TCHAR *szBuff ) { TCHAR header[16]; const TCHAR **strings; WORD eventType; HANDLE handle; WORD eventID, categoryID; int result; strings = malloc(sizeof(TCHAR *) * 3); if (!strings) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("SEM1")); return; } /* Build the source header */ switch(source_id) { case WRAPPER_SOURCE_WRAPPER: #ifdef WIN32 if (launcherSource) { _sntprintf( header, 16, TEXT("wrapperm") ); } else { _sntprintf( header, 16, TEXT("wrapper") ); } #else _sntprintf( header, 16, TEXT("wrapper") ); #endif break; case WRAPPER_SOURCE_PROTOCOL: _sntprintf( header, 16, TEXT("wrapperp") ); break; default: _sntprintf( header, 16, TEXT("jvm %d"), source_id ); header[15] = TEXT('\0'); /* Just in case we get lots of restarts. */ break; } /* Build event type by level */ switch(level) { case LEVEL_NOTICE: /* Will not get in here. */ case LEVEL_ADVICE: /* Will not get in here. */ case LEVEL_FATAL: eventType = EVENTLOG_ERROR_TYPE; break; case LEVEL_ERROR: case LEVEL_WARN: eventType = EVENTLOG_WARNING_TYPE; break; case LEVEL_STATUS: case LEVEL_INFO: case LEVEL_DEBUG: eventType = EVENTLOG_INFORMATION_TYPE; break; } /* Set the category id to the appropriate resource id. */ if ( source_id == WRAPPER_SOURCE_WRAPPER ) { categoryID = MSG_EVENT_LOG_CATEGORY_WRAPPER; } else if ( source_id == WRAPPER_SOURCE_PROTOCOL ) { categoryID = MSG_EVENT_LOG_CATEGORY_PROTOCOL; } else { /* Source is a JVM. */ switch ( source_id ) { case 1: categoryID = MSG_EVENT_LOG_CATEGORY_JVM1; break; case 2: categoryID = MSG_EVENT_LOG_CATEGORY_JVM2; break; case 3: categoryID = MSG_EVENT_LOG_CATEGORY_JVM3; break; case 4: categoryID = MSG_EVENT_LOG_CATEGORY_JVM4; break; case 5: categoryID = MSG_EVENT_LOG_CATEGORY_JVM5; break; case 6: categoryID = MSG_EVENT_LOG_CATEGORY_JVM6; break; case 7: categoryID = MSG_EVENT_LOG_CATEGORY_JVM7; break; case 8: categoryID = MSG_EVENT_LOG_CATEGORY_JVM8; break; case 9: categoryID = MSG_EVENT_LOG_CATEGORY_JVM9; break; default: categoryID = MSG_EVENT_LOG_CATEGORY_JVMXX; break; } } /* Place event in eventlog */ strings[0] = header; strings[1] = szBuff; strings[2] = 0; eventID = level; handle = RegisterEventSource( NULL, loginfoSourceName ); if( !handle ) return; result = ReportEvent( handle, /* handle to event log */ eventType, /* event type */ categoryID, /* event category */ MSG_EVENT_LOG_MESSAGE, /* event identifier */ NULL, /* user security identifier */ 2, /* number of strings to merge */ 0, /* size of binary data */ (const TCHAR**) strings, /* array of strings to merge */ NULL /* binary data buffer */ ); if (result == 0) { /* If there are any errors accessing the event log, like it is full, then disable its output. */ setSyslogLevelInt(LEVEL_NONE); /* Recurse so this error gets set in the log file and console. The syslog * output has been disabled so we will not get back here. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to write to the EventLog due to: %s"), getLastErrorText()); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Internally setting wrapper.syslog.loglevel=NONE to prevent further messages.")); } DeregisterEventSource( handle ); free( (void *) strings ); strings = NULL; } #else void sendLoginfoMessage( int source_id, int level, const TCHAR *szBuff ) { int eventType; /* Build event type by level */ switch( level ) { case LEVEL_FATAL: eventType = LOG_CRIT; break; case LEVEL_ERROR: eventType = LOG_ERR; break; case LEVEL_WARN: case LEVEL_STATUS: eventType = LOG_NOTICE; break; case LEVEL_INFO: eventType = LOG_INFO; break; case LEVEL_DEBUG: eventType = LOG_DEBUG; break; default: eventType = LOG_DEBUG; } /* openlog, closelog, and syslog all return void. */ openlog( loginfoSourceName, LOG_PID | LOG_NDELAY, currentLogfacilityLevel ); _tsyslog( eventType, szBuff ); closelog( ); } #endif #ifdef WIN32 #define CONSOLE_BLOCK_SIZE 1024 /* The following is an initial (max) size for the number of characters to try writing to WriteConsole at once. * See notes on the WriteConsole function below for details. */ size_t vWriteToConsoleMaxHeapBufferSize = 30000; size_t vWriteToConsoleBufferSize = 0; TCHAR *vWriteToConsoleBuffer = NULL; /** * Write a line of output to the console. * * @param hdl The handle to write to. Must be a valid handle. * * @return TRUE if successful, FALSE if the line was not written. */ int writeToConsole(HANDLE hdl, TCHAR *lpszFmt, ...) { va_list vargs; int cnt; size_t fullLen; size_t remainLen; size_t offset; size_t thisLen; DWORD wrote; #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("writeToConsole BEGIN\n")); #endif if (vWriteToConsoleBuffer == NULL) { vWriteToConsoleBufferSize = CONSOLE_BLOCK_SIZE * 2; vWriteToConsoleBuffer = malloc(sizeof(TCHAR) * vWriteToConsoleBufferSize); if (!vWriteToConsoleBuffer) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("WTC1")); return FALSE; } #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("Console Buffer Size = %d (Initial Size)\n"), vWriteToConsoleBufferSize); #endif if (logBufferGrowth) { /* This is queued as we can't use direct logging here. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Console Buffer Size initially set to %d characters."), vWriteToConsoleBufferSize); } } va_start(vargs, lpszFmt); /* The only way I could figure out how to write to the console * returned by AllocConsole when running as a service was to * do all of this special casing and use the handle to the new * console's stdout and the WriteConsole function. If anyone * puzzling over this code knows a better way of doing this * let me know. * WriteConsole takes a fixed buffer and does not do any expansions * We need to prepare the string to be displayed ahead of time. * This means storing the message into a temporary buffer. The * following loop will expand the global buffer to hold the current * message. It will grow as needed to handle any arbitrarily large * user message. The buffer needs to be able to hold all available * characters + a null TCHAR. * The _vsntprintf function will fill all available space and only * terminate the string if there is room. Because of this we need * to make sure and reserve room for the null terminator and add it * if needed below. */ while ((cnt = _vsntprintf(vWriteToConsoleBuffer, vWriteToConsoleBufferSize - 1, lpszFmt, vargs)) < 0) { #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("writeToConsole ProcessCount=%d\n"), cnt); #endif /* Expand the size of the buffer */ free(vWriteToConsoleBuffer); /* Increase the buffer by the CONSOLE_BLOCK_SIZE or an additional 10%, which ever is larger. * The goal here is to grow the buffer size quickly, but not waste too much memory. */ vWriteToConsoleBufferSize = __max(vWriteToConsoleBufferSize + CONSOLE_BLOCK_SIZE, vWriteToConsoleBufferSize + vWriteToConsoleBufferSize / 10); vWriteToConsoleBuffer = malloc(sizeof(TCHAR) * vWriteToConsoleBufferSize); if (!vWriteToConsoleBuffer) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("WTC2")); va_end( vargs ); return FALSE; } #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("Console Buffer Size = %d (Increased Size) ****************************************\n"), vWriteToConsoleBufferSize); #endif if (logBufferGrowth) { /* This is queued as we can't use direct logging here. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Console Buffer Size increased from to %d characters."), vWriteToConsoleBufferSize); } } #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("writeToConsole ProcessCount=%d\n"), cnt); #endif if (cnt == (vWriteToConsoleBufferSize - 1)) { /* The maximum number of characters were read. All of the characters fit in the available space, but because of the way the API works, the string was not null terminated. */ vWriteToConsoleBuffer[vWriteToConsoleBufferSize - 1] = '\0'; } va_end(vargs); #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("writeToConsole BufferSize=%d, MessageLen=%d, Message=[%s]\n"), vWriteToConsoleBufferSize, _tcslen(vWriteToConsoleBuffer), vWriteToConsoleBuffer); #endif /* The WriteConsole API is a nasty little beast. * It can accept a buffer that is up to 64KB in size, but they can't tell us exactly how much before hand. * The size on tests on a 64-bit XP system appear to be around 25000 characters. * Windows 7 returns success, but starts writing garbled characters after around 31397 characters. (Not sure if this number is system specific however.) * The problem is that this is highly dependent on the current system state. * We used to start with 32000, but now use 30000 to avoid problems on Windows 7. (Not sure if this is small enough to avoid the issue on all systems.) * Start with a large size for efficiency, but then reduce it automatically in a sticky way in 5% increments to get to a size that works. */ fullLen = _tcslen(vWriteToConsoleBuffer); remainLen = fullLen; offset = 0; while (remainLen > 0) { thisLen = __min(remainLen, vWriteToConsoleMaxHeapBufferSize); #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("writeToConsole write %d of %d characters\n"), thisLen, fullLen); #endif if (WriteConsole(hdl, &(vWriteToConsoleBuffer[offset]), (DWORD)thisLen, &wrote, NULL)) { #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("\nwriteToConsole (WriteConsole wrote %d of requested %d characters)\n"), wrote, thisLen); #endif /* Success. */ offset += thisLen; remainLen -= thisLen; #ifdef DEBUG_CONSOLE_OUTPUT if (remainLen > 0) { /* We have not written out the whole line which means there was no line feed. Add one or the debug output will be hard to read. */ _tprintf(TEXT("\nwriteToConsole (Previous line was incomplete)\n")); } #endif } else { /* Failed. */ #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("\nwriteToConsole (Fail WriteConsole wrote %d of requested %d characters)\n"), wrote, thisLen); #endif switch (getLastError()) { case ERROR_NOT_ENOUGH_MEMORY: /* This means that the max heap buffer size is too large and needs to be reduced. */ if (vWriteToConsoleMaxHeapBufferSize < 100) { _tprintf(TEXT("Not enough available HEAP to write to console.\n")); return FALSE; } vWriteToConsoleMaxHeapBufferSize = vWriteToConsoleMaxHeapBufferSize - vWriteToConsoleMaxHeapBufferSize / 20; #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("Usable Console HEAP Buffer Size reduced to = %d ****************************************\n"), vWriteToConsoleMaxHeapBufferSize); #endif if (logBufferGrowth) { /* This is queued as we can't use direct logging here. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Usable Console HEAP Buffer Size decreased to %d characters."), vWriteToConsoleMaxHeapBufferSize); } break; case ERROR_INVALID_FUNCTION: case ERROR_INVALID_HANDLE: /* This is a fairly normal thing to happen if the Wrapper is run without an actual console. * ERROR_INVALID_FUNCTION happens when we launch a forked elevated Wrapper. * ERROR_INVALID_HANDLE happens when the Wrapper is launched without its own console. * Log to debug so there is a note, but it is fine if this does not show up in commands where debug output can't be enabled. */ if (currentConsoleLevel <= LEVEL_DEBUG) { _tprintf(TEXT("A console does not exist. Disabling direct console output and falling back to using pipes.\n")); } consoleDirect = FALSE; return FALSE; default: _tprintf(TEXT("Failed to write to console: %s\n"), getLastErrorText()); return FALSE; } } } #ifdef DEBUG_CONSOLE_OUTPUT _tprintf(TEXT("writeToConsole END\n")); #endif return TRUE; } #endif /** * Does a search for all files matching the specified pattern and deletes all * but the most recent 'count' files. The files are sorted by their names. */ void limitLogFileCount(const TCHAR *current, const TCHAR *pattern, int sortMode, int count) { TCHAR **files; int index; int foundCurrent; #ifdef _DEBUG _tprintf(TEXT("limitLogFileCount(%s, %s, %d, %d)\n"), current, pattern, sortMode, count); #endif files = loggerFileGetFiles(pattern, sortMode); if (!files) { /* Failed */ return; } /* When this loop runs we keep the first COUNT files in the list and everything thereafter is deleted. */ foundCurrent = FALSE; index = 0; while (files[index]) { if (index < count) { #ifdef _DEBUG _tprintf(TEXT("Keep files[%d] %s\n"), index, files[index]); #endif if (_tcscmp(current, files[index]) == 0) { /* This is the current file, as expected. */ #ifdef _DEBUG _tprintf(TEXT(" Current\n")); #endif foundCurrent = TRUE; } } else { #ifdef _DEBUG _tprintf(TEXT("Delete files[%d] %s\n"), index, files[index]); #endif if (_tcscmp(current, files[index]) == 0) { /* This is the current file, we don't want to delete it. */ _tprintf(TEXT("Log file sort order would result in current log file being deleted: %s\n"), current); foundCurrent = TRUE; } else if (_tremove(files[index])) { _tprintf(TEXT("Unable to delete old log file: %s (%s)\n"), files[index], getLastErrorText()); } } index++; } /* Now if we did not find the current file, and there are files still in the directory, then we want to also delete the oldest one. Otherwise, the addition of the current file would result in too many files. */ if (!foundCurrent) { if (index >= count) { #ifdef _DEBUG _tprintf(TEXT("Delete files[%d] %s\n"), count - 1, files[count - 1]); #endif if (_tremove(files[count - 1])) { _tprintf(TEXT("Unable to delete old log file: %s (%s)\n"), files[count - 1], getLastErrorText()); } } } loggerFileFreeFiles(files); } /** * Sets the current uptime in seconds. * * @param uptime Uptime in seconds. * @param flipped TRUE when the uptime is no longer meaningful. */ void setUptime(int uptime, int flipped) { uptimeSeconds = uptime; uptimeFlipped = flipped; } int rollFailure = FALSE; /** * Rolls log files using the ROLLNUM system. */ void rollLogs() { int i; TCHAR rollNum[11]; #if defined(WIN32) && !defined(WIN64) struct _stat64i32 fileStat; #else struct stat fileStat; #endif int result; #ifdef _DEBUG _tprintf(TEXT("rollLogs()\n")); #endif if (!logFilePath) { return; } /* If the log file is currently open, it needs to be closed. */ if (logfileFP != NULL) { #ifdef _DEBUG _tprintf(TEXT("Closing logfile so it can be rolled...\n")); #endif fclose(logfileFP); logfileFP = NULL; currentLogFileName[0] = TEXT('\0'); } #ifdef _DEBUG _tprintf(TEXT("Rolling log files... (rollFailure=%d)\n"), rollFailure); #endif /* We don't know how many log files need to be rotated yet, so look. */ i = 0; do { i++; _sntprintf(rollNum, 11, TEXT("%d"), i); generateLogFileName(workLogFileName, currentLogFileNameSize, logFilePath, NULL, rollNum); result = _tstat(workLogFileName, &fileStat); #ifdef _DEBUG if (result == 0) { _tprintf(TEXT("Rolled log file %s exists.\n"), workLogFileName); } #endif } while (result == 0); /* Now, starting at the highest file rename them up by one index. */ for (; i > 1; i--) { _tcsncpy(currentLogFileName, workLogFileName, _tcslen(logFilePath) + 11); _sntprintf(rollNum, 11, TEXT("%d"), i - 1); generateLogFileName(workLogFileName, currentLogFileNameSize, logFilePath, NULL, rollNum); if ((logFileMaxLogFiles > 0) && (i > logFileMaxLogFiles) && (!logFilePurgePattern)) { /* The file needs to be deleted rather than rolled. If a purge pattern was not specified, * then the files will be deleted here. Otherwise they will be deleted below. */ #ifdef _DEBUG _tprintf(TEXT("Remove old log file %s\n"), workLogFileName); #endif if (_tremove(workLogFileName)) { #ifdef _DEBUG _tprintf(TEXT("Failed to remove old log file %s. err=%d\n"), workLogFileName, getLastError()); #endif if (getLastError() == 2) { /* The file did not exist. */ } else if (getLastError() == 3) { /* The path did not exist. */ } else { if (rollFailure == FALSE) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to delete old log file: %s (%s)"), workLogFileName, getLastErrorText()); } rollFailure = TRUE; generateLogFileName(currentLogFileName, currentLogFileNameSize, logFilePath, NULL, NULL); /* Set the name back so we don't cause a logfile name changed event. */ return; } } else { /* On Windows, in some cases if the file can't be deleted, we still get here without an error. Double check. */ if (_tstat(workLogFileName, &fileStat) == 0) { /* The file still existed. */ #ifdef _DEBUG _tprintf(TEXT("Failed to remove old log file %s\n"), workLogFileName); #endif if (rollFailure == FALSE) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to delete old log file: %s"), workLogFileName); } rollFailure = TRUE; generateLogFileName(currentLogFileName, currentLogFileNameSize, logFilePath, NULL, NULL); /* Set the name back so we don't cause a logfile name changed event. */ return; } #ifdef _DEBUG else { _tprintf(TEXT("Deleted %s\n"), workLogFileName); } #endif } } else { if (_trename(workLogFileName, currentLogFileName) != 0) { if (rollFailure == FALSE) { #ifdef WIN32 if (errno == EACCES) { /* This access denied message is treated as a special case, but the use by other applications issue only happens on Windows. */ /* Don't log this as with other errors as that would cause recursion. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to rename log file %s to %s. File is in use by another application."), workLogFileName, currentLogFileName); } else { #endif /* Don't log this as with other errors as that would cause recursion. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to rename log file %s to %s. (%s)"), workLogFileName, currentLogFileName, getLastErrorText()); #ifdef WIN32 } #endif } rollFailure = TRUE; generateLogFileName(currentLogFileName, currentLogFileNameSize, logFilePath, NULL, NULL); /* Set the name back so we don't cause a logfile name changed event. */ return; } #ifdef _DEBUG else { _tprintf(TEXT("Renamed %s to %s\n"), workLogFileName, currentLogFileName); } #endif } } /* Rename the current file to the #1 index position */ generateLogFileName(currentLogFileName, currentLogFileNameSize, logFilePath, NULL, NULL); if (_trename(currentLogFileName, workLogFileName) != 0) { if (rollFailure == FALSE) { if (getLastError() == 2) { /* File does not yet exist. */ } else if (getLastError() == 3) { /* Path does not yet exist. */ } else if (errno == 13) { /* Don't log this as with other errors as that would cause recursion. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to rename log file %s to %s. File is in use by another application."), currentLogFileName, workLogFileName); } else { /* Don't log this as with other errors as that would cause recursion. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to rename log file %s to %s. (%s)"), currentLogFileName, workLogFileName, getLastErrorText()); } } rollFailure = TRUE; generateLogFileName(currentLogFileName, currentLogFileNameSize, logFilePath, NULL, NULL); /* Set the name back so we don't cause a logfile name changed event. */ return; } #ifdef _DEBUG else { _tprintf(TEXT("Renamed %s to %s\n"), currentLogFileName, workLogFileName); } #endif /* Now limit the number of files using the standard method. */ if (logFileMaxLogFiles > 0) { if (logFilePurgePattern) { limitLogFileCount(currentLogFileName, logFilePurgePattern, logFilePurgeSortMode, logFileMaxLogFiles + 1); } } if (rollFailure == TRUE) { /* We made it here, but the rollFailure flag had been previously set. Make a note that we are back and then continue. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Logfile rolling is working again.")); } rollFailure = FALSE; /* Reset the current log file name as it is not being used yet. */ currentLogFileName[0] = TEXT('\0'); /* Log file was rolled, so we want to cause a logfile change event. */ } /** * Check to see whether or not the log file needs to be rolled. * This is only called when synchronized. */ void checkAndRollLogs(const TCHAR *nowDate) { long position; #if defined(WIN32) && !defined(WIN64) struct _stat64i32 fileStat; #else struct stat fileStat; #endif /* Depending on the roll mode, decide how to roll the log file. */ if (logFileRollMode & ROLL_MODE_SIZE) { /* Roll based on the size of the file. */ if (logFileMaxSize <= 0) { return; } /* Find out the current size of the file. If the file is currently open then we need to * use ftell to make sure that the buffered data is also included. */ if (logfileFP != NULL) { /* File is open */ if ((position = ftell(logfileFP)) < 0) { _tprintf(TEXT("Unable to get the current logfile size with ftell: %s\n"), getLastErrorText()); return; } } else { /* File is not open */ if (_tstat(logFilePath, &fileStat) != 0) { if (getLastError() == 2) { /* File does not yet exist. */ position = 0; } else if (getLastError() == 3) { /* Path does not exist. */ position = 0; } else { _tprintf(TEXT("Unable to get the current logfile size with stat: %s\n"), getLastErrorText()); return; } } else { position = fileStat.st_size; } } /* Does the log file need to rotated? */ if (position >= logFileMaxSize) { rollLogs(); } } else if (logFileRollMode & ROLL_MODE_DATE) { /* Roll based on the date of the log entry. */ if (_tcscmp(nowDate, logFileLastNowDate) != 0) { /* The date has changed. Close the file. */ if (logfileFP != NULL) { #ifdef _DEBUG _tprintf(TEXT("Closing logfile because the date changed...\n")); #endif fclose(logfileFP); logfileFP = NULL; } /* Always reset the name so the the log file name will be regenerated correctly. */ currentLogFileName[0] = TEXT('\0'); /* This will happen just before a new log file is created. * Check the maximum file count. */ if (logFileMaxLogFiles > 0) { /* We will check for too many files here and then clear the current log file name so it will be set later. */ generateLogFileName(currentLogFileName, currentLogFileNameSize, logFilePath, nowDate, NULL); if (logFilePurgePattern) { limitLogFileCount(currentLogFileName, logFilePurgePattern, logFilePurgeSortMode, logFileMaxLogFiles + 1); } else { generateLogFileName(workLogFileName, currentLogFileNameSize, logFilePath, TEXT("????????"), NULL); limitLogFileCount(currentLogFileName, workLogFileName, LOGGER_FILE_SORT_MODE_NAMES_DEC, logFileMaxLogFiles + 1); } currentLogFileName[0] = TEXT('\0'); workLogFileName[0] = TEXT('\0'); } } } } void log_printf_queue( int useQueue, int source_id, int level, const TCHAR *lpszFmt, ... ) { int threadId; int localWriteIndex; int localReadIndex; va_list vargs; int count; #if defined(UNICODE) && !defined(WIN32) TCHAR *format; size_t i; size_t len; #endif TCHAR *buffer; /* Start by processing any arguments so that we can store a simple string. */ #ifdef _DEBUG_QUEUE _tprintf(TEXT("log_printf_queue(%d, %d, %d, %S)\n"), useQueue, source_id, level, lpszFmt); #endif #if defined(UNICODE) && !defined(WIN32) if (wcsstr(lpszFmt, TEXT("%s")) != NULL) { /* On UNIX platforms string tokens must always use "%S" variables and not "%s". We can * not safely use malloc here as the call may have originated from a signal handler. * Copy the template into the formatMessages string reserved for this thread, replace * the tokens and then continue using that. This is a bit of overhead, but these async * messages are fairly rare and this greatly simplifies the code throughout the rest of * the application by making it possible to always use the "%s" syntax. */ threadId = getThreadId(); _tcsncpy(formatMessages[threadId], lpszFmt, QUEUED_BUFFER_SIZE); /* Terminate just in case the format was too long. */ formatMessages[threadId][QUEUED_BUFFER_SIZE - 1] = TEXT('\0'); format = formatMessages[threadId]; /* Replace the tokens. */ #ifdef _DEBUG_QUEUE _tprintf(TEXT("Replacing string tokens.\n")); _tprintf(TEXT(" From: %S\n"), format); #endif len = wcslen(format); if (len > 0) { for (i = 0; i < len; i++) { if ((i > 0) && (format[i - 1] == TEXT('%')) && (format[i] == TEXT('s'))) { /* Make sure the '%' was not escaped. */ if ((i > 1) && (format[i - 2] == TEXT('%'))) { /* Escaped. Do nothing. */ } else { /* 's' needs to be changed to 'S' */ format[i] = TEXT('S'); } } } } #ifdef _DEBUG_QUEUE _tprintf(TEXT(" To: %S\n"), format); #endif lpszFmt = format; } #endif /** For queued logging, we have a fixed length buffer to work with. Just to make it easy to catch * problems, always use the same sized fixed buffer even if we will be using the non-queued logging. */ if (useQueue) { /* Care needs to be taken both with this code and the code below to get done as quick as possible. * It is generally safe because each thread has its own queue. The only danger is if a message is * being queued while that thread is interupted by a signal. If things are setup correctly however * then non-signal threads should not be here in the first place. */ threadId = getThreadId(); localWriteIndex = queueWriteIndex[threadId]; localReadIndex = queueReadIndex[threadId]; if ((localWriteIndex == localReadIndex - 1) || ((localWriteIndex == QUEUE_SIZE - 1) && (localReadIndex == 0))) { _tprintf(TEXT("WARNING log queue overflow for thread[%d]:%d:%d dropping entry: %s\n"), threadId, localWriteIndex, localReadIndex, lpszFmt); return; } /* Get a reference to the message buffer we will use. */ buffer = queueMessages[threadId][queueWriteIndex[threadId]]; } else { /* This will not be queued so we can use malloc to create a new buffer. */ buffer = malloc(sizeof(TCHAR) * QUEUED_BUFFER_SIZE); if (!buffer) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("PQ1")); return; } /* For compiler */ threadId = -1; localWriteIndex = -1; } /* Now actually generate our buffer. */ va_start(vargs, lpszFmt); count = _vsntprintf(buffer, QUEUED_BUFFER_SIZE_USABLE, lpszFmt, vargs); va_end(vargs); /* vswprintf returns -1 on overflow. */ if ((count < 0) || (count >= QUEUED_BUFFER_SIZE_USABLE - 1)) { /* The expanded message was too big to fit into the buffer. * On Windows, it writes as much as it can so we can make it look pretty. * But on other platforms, nothing is written so we need a message. * It is illegal to do any mallocs in here, so there is notheing we can really do on UNIX. */ #if defined(WIN32) /* To be safe, make sure we are null terminated. */ buffer[QUEUED_BUFFER_SIZE_USABLE - 1] = 0; _tcsncat(buffer, TEXT("..."), QUEUED_BUFFER_SIZE); #else /* Write an error string that we know will fit. This doesn't need to be localized as it should be caught in testing. */ _sntprintf(buffer, QUEUED_BUFFER_SIZE, TEXT("(Message too long to be logged as a queued message. Please report this.)")); #endif } if (useQueue) { #ifdef _DEBUG_QUEUE _tprintf(TEXT("LOG ENQUEUE[%d] Thread[%d]: %s\n"), localWriteIndex, threadId, buffer); #endif /* Store additional information about the call. */ queueSourceIds[threadId][localWriteIndex] = source_id; queueLevels[threadId][localWriteIndex] = level; /* Lastly increment and wrap the write index. */ queueWriteIndex[threadId]++; if (queueWriteIndex[threadId] >= QUEUE_SIZE) { queueWriteIndex[threadId] = 0; queueWrapped[threadId] = 1; } } else { /* Make a normal logging call with our new buffer. Parameters are already expanded. */ log_printf(source_id, level, #if defined(UNICODE) && !defined(WIN32) TEXT("%S"), #else TEXT("%s"), #endif buffer); free(buffer); } } /** * Perform any required logger maintenance at regular intervals. * * One operation is to log any queued messages. This must be done very * carefully as it is possible that a signal handler could be thrown at * any time as this function is being executed. */ void maintainLogger() { int localWriteIndex; int source_id; int level; int threadId; TCHAR *buffer; int logFileChanged; TCHAR *logFileCopy; /* Check to see if there is a pending log file change notification. Do this first as we could * generate our own here as well. It is important that we do our best to keep them in order. * Grab it and clear the reference quick in case another is set. This order is thread safe. */ if (pendingLogFileChange) { /* Lock the logging mutex. */ if (lockLoggingMutex()) { return; } logFileCopy = pendingLogFileChange; pendingLogFileChange = NULL; /* Release the lock we have on the logging mutex so that other threads can get in. */ if (releaseLoggingMutex()) { return; } /* Now see if a log file name was queued, using our local copy. */ if (logFileCopy) { #ifdef _DEBUG _tprintf(TEXT("Sending notification of queued log file name change: %s"), logFileCopy); #endif logFileChangedCallback(logFileCopy); free(logFileCopy); logFileCopy = NULL; } } for (threadId = 0; threadId < WRAPPER_THREAD_COUNT; threadId++) { /* NOTE - The queue variables are not synchronized so we need to access them * carefully and assume that data could possibly be corrupted. */ localWriteIndex = queueWriteIndex[threadId]; /* Snapshot the value to maintain a constant reference. */ if ( queueReadIndex[threadId] != localWriteIndex ) { logFileChanged = FALSE; logFileCopy = NULL; /* Lock the logging mutex. */ if (lockLoggingMutex()) { return; } /* Empty the queue of any logged messages. */ localWriteIndex = queueWriteIndex[threadId]; /* Snapshot the value to maintain a constant reference. */ while (queueReadIndex[threadId] != localWriteIndex) { /* Snapshot the values in the queue at that index. */ source_id = queueSourceIds[threadId][queueReadIndex[threadId]]; level = queueLevels[threadId][queueReadIndex[threadId]]; buffer = queueMessages[threadId][queueReadIndex[threadId]]; /* The buffer is static in the queue and will be reused. */ #ifdef _DEBUG_QUEUE _tprintf(TEXT("LOG QUEUED[%d]: %s\n"), queueReadIndex[threadId], buffer ); #endif logFileChanged = log_printf_message(source_id, level, threadId, TRUE, buffer, TRUE); if (logFileChanged) { logFileCopy = malloc(sizeof(TCHAR) * (_tcslen(currentLogFileName) + 1)); if (!logFileCopy) { _tprintf(TEXT("Out of memory in logging code (%s)\n"), TEXT("ML1")); } else { _tcsncpy(logFileCopy, currentLogFileName, _tcslen(currentLogFileName) + 1); } } #ifdef _DEBUG_QUEUE _tprintf(TEXT(" Queue lw=%d, qw=%d, qr=%d\n"), localWriteIndex, queueWriteIndex[threadId], queueReadIndex[threadId]); #endif /* Clear the string we just wrote. */ buffer[0] = TEXT('\0'); queueReadIndex[threadId]++; if ( queueReadIndex[threadId] >= QUEUE_SIZE ) { queueReadIndex[threadId] = 0; } } /* Release the lock we have on the logging mutex so that other threads can get in. */ if (releaseLoggingMutex()) { if (logFileChanged && logFileCopy) { free(logFileCopy); } return; } /* Now that we are no longer in the semaphore, register the change of the logfile. */ if (logFileChanged && logFileCopy) { logFileChangedCallback(logFileCopy); free(logFileCopy); } } } } wrapper_3.5.26_src/src/c/logger.h100644 0 0 23530 12440202301 14017 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * Author: * Johan Sorlin * Leif Mortenson */ #ifndef _LOGGER_H #define _LOGGER_H /* If defined, output debug information about console output. */ /*#define DEBUG_CONSOLE_OUTPUT*/ #ifdef _DEBUG #define _DEBUG_QUEUE #endif #ifdef WIN32 #include #define LOG_USER (1<<3) #endif #ifndef DWORD #define DWORD unsigned long #endif #include "logger_base.h" /* * * Log source constants * * */ #define WRAPPER_SOURCE_WRAPPER -1 #define WRAPPER_SOURCE_PROTOCOL -2 /* * * Log thread constants * * */ /* These are indexes in an array so they must be sequential, start * with zero and be one less than the final WRAPPER_THREAD_COUNT */ #define WRAPPER_THREAD_CURRENT -1 #define WRAPPER_THREAD_SIGNAL 0 #define WRAPPER_THREAD_MAIN 1 #define WRAPPER_THREAD_SRVMAIN 2 #define WRAPPER_THREAD_TIMER 3 #define WRAPPER_THREAD_JAVAIO 4 #define WRAPPER_THREAD_STARTUP 5 #define WRAPPER_THREAD_COUNT 6 #define MAX_LOG_SIZE 4096 #ifdef WIN32 #else /* A special prefix on log messages that can be bassed through from a forked process so the parent will handle the log message correctly. */ #define LOG_FORK_MARKER TEXT("#!#WrApPeR#!#") #define LOG_SPECIAL_MARKER TEXT("#!#WrApPeRsPeCiAl#!#") #endif /* Default log formats */ #define LOG_FORMAT_LOGFILE_DEFAULT TEXT("LPTM") #define LOG_FORMAT_CONSOLE_DEFAULT TEXT("PM") /* * * Log file roll mode constants * * */ #define ROLL_MODE_UNKNOWN 0 #define ROLL_MODE_NONE 1 #define ROLL_MODE_SIZE 2 #define ROLL_MODE_WRAPPER 4 #define ROLL_MODE_JVM 8 #define ROLL_MODE_SIZE_OR_WRAPPER ROLL_MODE_SIZE + ROLL_MODE_WRAPPER #define ROLL_MODE_SIZE_OR_JVM ROLL_MODE_SIZE + ROLL_MODE_JVM #define ROLL_MODE_DATE 16 #define ROLL_MODE_DATE_TOKEN TEXT("YYYYMMDD") /* This can be called from within logging code that would otherwise get stuck in recursion. * Log to the console exactly when it happens and then also try to get it into the log * file at the next oportunity. */ extern void outOfMemoryQueued(const TCHAR *context, int id); extern void outOfMemory(const TCHAR *context, int id); #ifdef _DEBUG /** * Used to dump memory directly to the log file in both HEX and readable format. * Useful in debugging applications to track down memory overflows etc. * * @param label A label that will be prepended on all lines of output. * @param memory The memory to be dumped. * @param len The length of the memory to be dumped. */ extern void log_dumpHex(TCHAR *label, TCHAR *memory, size_t len); #endif /** * Sets the number of milliseconds to allow logging to take before a warning is logged. * Defaults to 0 for no limit. Possible values 0 to 3600000. * * @param threshold Warning threashold. */ extern void setLogWarningThreshold(int threshold); /** * Sets the log levels to a silence so we never output anything. */ extern void setSilentLogLevels(); /** * Sets the console log levels to a simple format for help and usage messages. */ extern void setSimpleLogLevels(); #ifdef WIN32 /** * This sets a flag which tells the logger that alternate source labels should be used to indicate that the current process is a launcher. */ extern void setLauncherSource(); #endif /** * Used for testing to set a pause into the next log entry made. * * @param pauseTime Number of seconds to pause, 0 pauses indefinitely. */ extern void setPauseTime(int pauseTime); /** * Set to true to cause changes in internal buffer sizes to be logged. Useful for debugging. * * @param log TRUE if changes should be logged. */ void setLogBufferGrowth(int log); /* * Logfile functions * */ extern int isLogfileAccessed(); /** * Sets the log file to be used. If the specified file is not absolute then * it will be resolved into an absolute path. If there are any problems with * the path, like a directory not existing then the call will fail and the * cause will be written to the existing log. * * @param log_file_path Log file to start using. * @param workingDir The current working directory, used for relative paths. * This will be NULL if this is part of the bootstrap process, * in which case we should not attempt to resolve the absolute * path. * @param preload TRUE if called as part of the preload process. We use this to * suppress double warnings. * * @return TRUE if there were any problems. */ extern int setLogfilePath( const TCHAR *log_file_path, const TCHAR *workingDir, int preload); /** * Returns the default logfile. */ extern const TCHAR *getDefaultLogfilePath(); /** * Returns a reference to the currect log file path. * This return value may be changed at any time if the log file is rolled. */ extern const TCHAR *getLogfilePath(); /** * Returns a snapshot of the current log file path. This call safely gets the current path * and returns a copy. It is the responsibility of the caller to free up the memory on * return. Could return null if there was an error. */ extern TCHAR *getCurrentLogfilePath(); /** * Check the directory of the current logfile path to make sure it is writable. * If there are any problems, log a warning. * * @return TRUE if there were any problems. */ extern int checkLogfileDir(); extern int getLogfileRollModeForName( const TCHAR *logfileRollName ); extern void setLogfileRollMode(int log_file_roll_mode); extern int getLogfileRollMode(); extern void setLogfileUmask(int log_file_umask); extern void setLogfileFormat( const TCHAR *log_file_format ); extern void setLogfileLevelInt(int log_file_level); extern int getLogfileLevelInt(); extern void setLogfileLevel( const TCHAR *log_file_level ); extern void setLogfileMaxFileSize( const TCHAR *max_file_size ); extern void setLogfileMaxFileSizeInt(int max_file_size); extern void setLogfileMaxLogFiles(int max_log_files); extern void setLogfilePurgePattern(const TCHAR *pattern); extern void setLogfilePurgeSortMode(int sortMode); extern DWORD getLogfileActivity(); /** Sets the auto flush log file flag. */ extern void setLogfileAutoFlush(int autoFlush); /** Sets the auto close log file flag. */ extern void setLogfileAutoClose(int autoClose); /** Closes the logfile if it is open. */ extern void closeLogfile(); /** Flushes any buffered logfile output to the disk. */ extern void flushLogfile(); /* * Console functions * */ extern void setConsoleLogFormat( const TCHAR *console_log_format ); extern void setConsoleLogLevelInt(int console_log_level); extern int getConsoleLogLevelInt(); extern void setConsoleLogLevel( const TCHAR *console_log_level ); extern void setConsoleFlush(int flush); #ifdef WIN32 extern void setConsoleDirect(int direct); #endif extern void setConsoleFatalToStdErr(int toStdErr); extern void setConsoleErrorToStdErr(int toStdErr); extern void setConsoleWarnToStdErr(int toStdErr); /* * Syslog/eventlog functions * */ extern void setSyslogLevelInt(int loginfo_level); extern int getSyslogLevelInt(); extern void setSyslogLevel( const TCHAR *loginfo_level ); extern void setSyslogSplitMessages(int splitMessages); #ifndef WIN32 extern void setSyslogFacility( const TCHAR *loginfo_level ); #endif extern void setSyslogEventSourceName( const TCHAR *event_source_name ); extern int registerSyslogMessageFile(); extern int unregisterSyslogMessageFile(); extern void resetDuration(); extern int getLowLogLevel(); /* * General log functions * */ extern int initLogging(void (*logFileChanged)(const TCHAR *logFile)); extern int disposeLogging(); extern void setUptime(int uptime, int flipped); extern void rollLogs(); extern int getLogLevelForName( const TCHAR *logLevelName ); #ifndef WIN32 extern int getLogFacilityForName( const TCHAR *logFacilityName ); #endif extern void logRegisterThread(int thread_id); /** * The log_printf function logs a message to the configured log targets. * * This method can be used safely in most cases. See the log_printf_queue * funtion for the exceptions. */ extern void log_printf( int source_id, int level, const TCHAR *lpszFmt, ... ); /** * The log_printf_queue function is less efficient than the log_printf * function and will cause logged messages to be logged out of order from * those logged with log_printf because the messages are queued and then * logged from another thread. * * Use of this function is required in cases where the thread may possibly * be a signal callback. In these cases, it is possible for the original * thread to have been suspended within a log_printf call. If the signal * thread then attempted to call log_printf, it would result in a deadlock. */ extern void log_printf_queue( int useQueue, int source_id, int level, const TCHAR *lpszFmt, ... ); extern void maintainLogger(); extern void invalidMultiByteSequence(const TCHAR *context, int id); #endif wrapper_3.5.26_src/src/c/logger_base.h100644 0 0 3316 12440202301 14771 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #ifndef _LOGGER_BASE_H #define _LOGGER_BASE_H #include "wrapper_i18n.h" /* * * Log level constants * * */ /* No logging at all. */ #define LEVEL_NONE 9 /* Notice messages which should always be displayed. These never go to the syslog. */ #define LEVEL_NOTICE 8 /* Advisor messages which should always be displayed. These never go to the syslog. */ #define LEVEL_ADVICE 7 /* Too many restarts, unable to start etc. Case when the Wrapper is forced to exit. */ #define LEVEL_FATAL 6 /* JVM died, hung messages */ #define LEVEL_ERROR 5 /* Warning messages. */ #define LEVEL_WARN 4 /* Started, Stopped, Restarted messages. */ #define LEVEL_STATUS 3 /* Copyright message. and logged console output. */ #define LEVEL_INFO 2 /* Current debug messages */ #define LEVEL_DEBUG 1 /* Unknown level */ #define LEVEL_UNKNOWN 0 /* The maximum length of a source string, not including the null character. */ #define MAX_SOURCE_LENGTH 8 /* * * Function predeclaration * * */ #define strcmpIgnoreCase(str1, str2) _tcsicmp(str1, str2) /** * Returns a textual error message of the last error encountered. * * @return The last error message. */ extern const TCHAR* getLastErrorText(); /** * Returns the last error number. * * @return The last error number. */ extern int getLastError(); extern void outOfMemory(const TCHAR *context, int id); #endif wrapper_3.5.26_src/src/c/logger_file.c100644 0 0 44021 12440202301 15007 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * Author: * Tanuki Software Development Team */ #ifdef WIN32 #include #include #else #include #include #endif #ifdef WIN32 #include #endif #include "logger.h" #include "logger_file.h" #include "wrapper_i18n.h" #define FILES_CHUNK 5 #ifndef TRUE #define TRUE -1 #endif #ifndef FALSE #define FALSE 0 #endif /** * Returns a valid sort mode given a name: "TIMES", "NAMES_ASC", "NAMES_DEC". * In the event of an invalid value, TIMES will be returned. */ int loggerFileGetSortMode(const TCHAR *modeName) { if (strcmpIgnoreCase(modeName, TEXT("NAMES_ASC")) == 0) { return LOGGER_FILE_SORT_MODE_NAMES_ASC; } else if (strcmpIgnoreCase(modeName, TEXT("NAMES_DEC")) == 0) { return LOGGER_FILE_SORT_MODE_NAMES_DEC; } else { return LOGGER_FILE_SORT_MODE_TIMES; } } #ifdef WIN32 int sortFilesTimes(TCHAR **files, __time64_t *fileTimes, int cnt) { #else int sortFilesTimes(TCHAR **files, time_t *fileTimes, int cnt) { #endif int i, j; TCHAR *temp; #ifdef WIN32 __time64_t tempTime; #else time_t tempTime; #endif for (i = 0; i < cnt; i++) { for (j = 0; j < cnt - 1; j++) { if (fileTimes[j] < fileTimes[j + 1]) { temp = files[j + 1]; tempTime = fileTimes[j + 1]; files[j + 1] = files[j]; fileTimes[j + 1] = fileTimes[j]; files[j] = temp; fileTimes[j] = tempTime; } } } return TRUE; } /** * Compares two strings. Returns 0 if they are equal, -1 if file1 is bigger, 1 if file2 is bigger. */ int compareFileNames(const TCHAR *file1, const TCHAR *file2) { int pos1, pos2; TCHAR c1, c2; int numeric1, numeric2; long int num1, num2; int afterNumber = FALSE; pos1 = 0; pos2 = 0; while (TRUE) { c1 = file1[pos1]; c2 = file2[pos2]; /*printf(" file1[%d]=%d, file2[%d]=%d\n", pos1, c1, pos2, c2);*/ /* Did we find the null. */ if (c1 == 0) { if (c2 == 0) { return 0; } else { return 1; } } else { if (c2 == 0) { return -1; } else { /* Continue. */ } } /* We have two characters. */ numeric1 = ((c1 >= TEXT('0')) && (c1 <= TEXT('9'))); numeric2 = ((c2 >= TEXT('0')) && (c2 <= TEXT('9'))); /* See if one or both of the strings is numeric. */ if (numeric1) { if (numeric2) { /* Both are numeric, we need to start comparing the two file names as integer values. */ num1 = c1 - TEXT('0'); c1 = file1[pos1 + 1]; while ((c1 >= TEXT('0')) && (c1 <= TEXT('9'))) { num1 = num1 * 10 + (c1 - TEXT('0')); pos1++; c1 = file1[pos1 + 1]; } num2 = c2 - TEXT('0'); c2 = file2[pos2 + 1]; while ((c2 >= TEXT('0')) && (c2 <= TEXT('9'))) { num2 = num2 * 10 + (c2 - TEXT('0')); pos2++; c2 = file2[pos2 + 1]; } /*printf(" num1=%ld, num2=%ld\n", num1, num2);*/ if (num1 > num2) { return -1; } else if (num2 > num1) { return 1; } else { /* Equal, continue. */ } afterNumber = TRUE; } else { /* 1 is numeric, 2 is not. */ if (afterNumber) { return -1; } else { return 1; } } } else { if (numeric2) { /* 1 is not, 2 is numeric. */ if (afterNumber) { return 1; } else { return -1; } } else { /* Neither is numeric. */ } } /* Compare the characters as is. */ if (c1 > c2) { return -1; } else if (c2 > c1) { return 1; } else { /* Equal, continue. */ if ((c1 == TEXT('.')) || (c1 == TEXT('-')) || (c1 == TEXT('_'))) { } else { afterNumber = FALSE; } } pos1++; pos2++; } } int sortFilesNamesAsc(TCHAR **files, int cnt) { int i, j; TCHAR *temp; int cmp; for (i = 0; i < cnt; i++) { for (j = 0; j < cnt - 1; j++) { cmp = compareFileNames(files[j], files[j+1]); if (cmp < 0) { temp = files[j + 1]; files[j + 1] = files[j]; files[j] = temp; } } } return TRUE; } int sortFilesNamesDec(TCHAR **files, int cnt) { int i, j; TCHAR *temp; int cmp; for (i = 0; i < cnt; i++) { for (j = 0; j < cnt - 1; j++) { cmp = compareFileNames(files[j], files[j+1]); if (cmp > 0) { temp = files[j + 1]; files[j + 1] = files[j]; files[j] = temp; } } } return TRUE; } /** * Returns a NULL terminated list of file names within the specified pattern. * The files will be sorted new to old for TIMES. Then incremental ordering * for NAMES. The numeric components of the names will be treated as * numbers and sorted accordingly. */ TCHAR** loggerFileGetFiles(const TCHAR* pattern, int sortMode) { int cnt; int filesSize; TCHAR **files; #ifdef WIN32 int i; size_t dirLen; TCHAR *c; TCHAR *dirPart; intptr_t handle; struct _tfinddata64_t fblock; size_t fileLen; TCHAR **newFiles; __time64_t *fileTimes; __time64_t *newFileTimes; #else #ifdef WRAPPER_FILE_DEBUG int i; #endif int result; glob_t g; int findex; time_t *fileTimes; struct stat fileStat; #endif #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT("loggerFileGetFiles(%s, %d)\n"), pattern, sortMode); #endif #ifdef WIN32 cnt = 0; /* Initialize the files array. */ filesSize = FILES_CHUNK; files = malloc(sizeof(TCHAR *) * filesSize); if (!files) { outOfMemoryQueued(TEXT("WFGF"), 1); return NULL; } memset(files, 0, sizeof(TCHAR *) * filesSize); fileTimes = malloc(sizeof(__time64_t) * filesSize); if (!fileTimes) { outOfMemoryQueued(TEXT("WFGF"), 2); free(files); return NULL; } memset(fileTimes, 0, sizeof(__time64_t) * filesSize); /* Extract any path information from the beginning of the file */ c = max(_tcsrchr(pattern, TEXT('\\')), _tcsrchr(pattern, TEXT('/'))); if (c == NULL) { /* No directory component */ dirPart = malloc(sizeof(TCHAR) * 1); if (!dirPart) { outOfMemoryQueued(TEXT("WFGF"), 3); return NULL; } dirPart[0] = TEXT('\0'); dirLen = 0; } else { /* extract the directory. */ dirLen = c - pattern + 1; dirPart = malloc(sizeof(TCHAR) * (dirLen + 1)); if (!dirPart) { outOfMemoryQueued(TEXT("WFGF"), 4); return NULL; } _tcsncpy(dirPart, pattern, dirLen); dirPart[dirLen] = TEXT('\0'); } #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT(" dirPart=[%s]\n"), dirPart); #endif /* Get the first file. */ #ifdef _IA64_ /* On Itanium, the first parameter is not a "const". If you don't cast it, then you have a warning */ if ((handle = _tfindfirst64((TCHAR *)pattern, &fblock)) > 0) { #else if ((handle = _tfindfirst64(pattern, &fblock)) > 0) { #endif if ((_tcscmp(fblock.name, TEXT(".")) != 0) && (_tcscmp(fblock.name, TEXT("..")) != 0)) { fileLen = _tcslen(fblock.name); files[cnt] = malloc((_tcslen(dirPart) + _tcslen(fblock.name) + 1) * sizeof(TCHAR)); if (!files[cnt]) { outOfMemoryQueued(TEXT("WFGF"), 5); free(fileTimes); loggerFileFreeFiles(files); free(dirPart); return NULL; } _sntprintf(files[cnt], _tcslen(dirPart) + _tcslen(fblock.name) + 1, TEXT("%s%s"), dirPart, fblock.name); fileTimes[cnt] = fblock.time_write; #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT(" files[%d]=%s, %ld\n"), cnt, files[cnt], fileTimes[cnt]); #endif cnt++; } /* Look for additional files. */ while (_tfindnext64(handle, &fblock) == 0) { if ((_tcscmp(fblock.name, TEXT(".")) != 0) && (_tcscmp(fblock.name, TEXT("..")) != 0)) { /* Make sure we have enough room in the files array. */ if (cnt >= filesSize - 1) { newFiles = malloc(sizeof(TCHAR *) * (filesSize + FILES_CHUNK)); if (!newFiles) { outOfMemoryQueued(TEXT("WFGF"), 6); free(fileTimes); loggerFileFreeFiles(files); free(dirPart); return NULL; } memset(newFiles, 0, sizeof(TCHAR *) * (filesSize + FILES_CHUNK)); newFileTimes = malloc(sizeof(__time64_t) * (filesSize + FILES_CHUNK)); if (!newFileTimes) { outOfMemoryQueued(TEXT("WFGF"), 7); free(newFiles); free(fileTimes); loggerFileFreeFiles(files); free(dirPart); return NULL; } memset(newFileTimes, 0, sizeof(__time64_t) * (filesSize + FILES_CHUNK)); for (i = 0; i < filesSize; i++) { newFiles[i] = files[i]; newFileTimes[i] = fileTimes[i]; } free(files); free(fileTimes); files = newFiles; fileTimes = newFileTimes; filesSize += FILES_CHUNK; #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT(" increased files to %d\n"), filesSize); #endif } fileLen = _tcslen(fblock.name); files[cnt] = malloc((_tcslen(dirPart) + _tcslen(fblock.name) + 1) * sizeof(TCHAR)); if (!files[cnt]) { outOfMemoryQueued(TEXT("WFGF"), 8); free(fileTimes); loggerFileFreeFiles(files); free(dirPart); return NULL; } _sntprintf(files[cnt], _tcslen(dirPart) + _tcslen(fblock.name) + 1, TEXT("%s%s"), dirPart, fblock.name); fileTimes[cnt] = fblock.time_write; #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT(" files[%d]=%s, %ld\n"), cnt, files[cnt], fileTimes[cnt]); #endif cnt++; } } /* Close the file search */ _findclose(handle); } if (cnt <= 0) { if (errno == ENOENT) { /* No files matched. */ #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT(" No files matched.\n")); #endif } else { /* Encountered an error of some kind. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Error listing files, %s: %s"), pattern, getLastErrorText()); free(fileTimes); loggerFileFreeFiles(files); return NULL; } } #else /* Unix */ #ifdef UNICODE char* cPattern; size_t req; req = wcstombs(NULL, pattern, 0) + 1; cPattern = malloc(req); if(!cPattern) { outOfMemoryQueued(TEXT("WFGF"), 8); return NULL; } wcstombs(cPattern, pattern, req); result = glob(cPattern, GLOB_MARK | GLOB_NOSORT, NULL, &g); free(cPattern); #else result = glob(pattern, GLOB_MARK | GLOB_NOSORT, NULL, &g); #endif cnt = 0; if (!result) { if (g.gl_pathc > 0) { filesSize = g.gl_pathc + 1; files = malloc(sizeof(TCHAR *) * filesSize); if (!files) { outOfMemoryQueued(TEXT("WFGF"), 9); return NULL; } memset(files, 0, sizeof(TCHAR *) * filesSize); fileTimes = malloc(sizeof(time_t) * filesSize); if (!fileTimes) { outOfMemoryQueued(TEXT("WFGF"), 10); loggerFileFreeFiles(files); return NULL; } memset(fileTimes, 0, sizeof(time_t) * filesSize); for (findex = 0; findex < g.gl_pathc; findex++) { #ifdef UNICODE req = mbstowcs(NULL, g.gl_pathv[findex], 0); if (req == (size_t)-1) { invalidMultiByteSequence(TEXT("GLET"), 1); } files[cnt] = malloc((req + 1) * sizeof(TCHAR)); if (!files[cnt]) { outOfMemoryQueued(TEXT("WFGF"), 11); free(fileTimes); loggerFileFreeFiles(files); return NULL; } mbstowcs(files[cnt], g.gl_pathv[findex], req + 1); #else files[cnt] = malloc((strlen(g.gl_pathv[findex]) + 1)); if (!files[cnt]) { outOfMemoryQueued(TEXT("WFGF"), 11); free(fileTimes); loggerFileFreeFiles(files); return NULL; } strncpy(files[cnt], g.gl_pathv[findex], strlen(g.gl_pathv[findex]) + 1); #endif /* Only try to get the modified time if it is really necessary. */ if (sortMode == LOGGER_FILE_SORT_MODE_TIMES) { if (!_tstat(files[cnt], &fileStat)) { fileTimes[cnt] = fileStat.st_mtime; } else { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to stat %s: %s"), files[cnt], getLastErrorText()); } } #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT(" files[%d]=%s, %ld\n"), cnt, files[cnt], fileTimes[cnt]); #endif cnt++; } } else { #ifdef WRAPPER_FILE_DEBUG printf(" No files matched.\n"); #endif /* No files, but we still need the array. */ filesSize = 1; files = malloc(sizeof(TCHAR *) * filesSize); if (!files) { outOfMemoryQueued(TEXT("WFGF"), 12); return NULL; } memset(files, 0, sizeof(TCHAR *) * filesSize); fileTimes = malloc(sizeof(time_t) * filesSize); if (!fileTimes) { free(files); outOfMemoryQueued(TEXT("WFGF"), 13); return NULL; } memset(fileTimes, 0, sizeof(time_t) * filesSize); } globfree(&g); } else if (result == GLOB_NOMATCH) { #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT(" No files matched.\n")); #endif /* No files, but we still need the array. */ filesSize = 1; files = malloc(sizeof(TCHAR *) * filesSize); if (!files) { outOfMemoryQueued(TEXT("WFGF"), 14); return NULL; } memset(files, 0, sizeof(TCHAR *) * filesSize); fileTimes = malloc(sizeof(time_t) * filesSize); if (!fileTimes) { free(files); outOfMemoryQueued(TEXT("WFGF"), 15); return NULL; } memset(fileTimes, 0, sizeof(time_t) * filesSize); } else { /* Encountered an error of some kind. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Error listing files, %s: %s"), pattern, getLastErrorText()); return NULL; } #endif if (sortMode == LOGGER_FILE_SORT_MODE_TIMES) { if (!sortFilesTimes(files, fileTimes, cnt)) { /* Failed. Reported. */ free(fileTimes); loggerFileFreeFiles(files); return NULL; } } else if (sortMode == LOGGER_FILE_SORT_MODE_NAMES_DEC) { if (!sortFilesNamesDec(files, cnt)) { /* Failed. Reported. */ free(fileTimes); loggerFileFreeFiles(files); return NULL; } } else { /* LOGGER_FILE_SORT_MODE_NAMES_ASC */ if (!sortFilesNamesAsc(files, cnt)) { /* Failed. Reported. */ free(fileTimes); loggerFileFreeFiles(files); return NULL; } } #ifdef WRAPPER_FILE_DEBUG _tprintf(TEXT(" Sorted:\n")); for (i = 0; i < cnt; i++) { _tprintf(TEXT(" files[%d]=%s, %ld\n"), i, files[i], fileTimes[i]); } _tprintf(TEXT("loggerFileGetFiles(%s, %d) END\n"), pattern, sortMode); #endif free(fileTimes); return files; } /** * Frees the array of file names returned by loggerFileGetFiles() */ void loggerFileFreeFiles(TCHAR** files) { int i; i = 0; while (files[i]) { free(files[i]); i++; } free(files); } #ifdef LOGGER_FILE_DEBUG void loggerFileTests() { TCHAR** files; printf("Start loggerFileTests\n"); files = loggerFileGetFiles((TEXT("../logs/*.log*"), LOGGER_FILE_SORT_MODE_TIMES); if (files) { loggerFileFreeFiles(files); } files = loggerFileGetFiles(TEXT("../logs/*.log*"), LOGGER_FILE_SORT_MODE_NAMES_ASC); if (files) { loggerFileFreeFiles(files); } files = loggerFileGetFiles(TEXT("../logs/*.log*"), LOGGER_FILE_SORT_MODE_NAMES_DEC); if (files) { loggerFileFreeFiles(files); } printf("End loggerFileTests\n"); } #endif wrapper_3.5.26_src/src/c/logger_file.h100644 0 0 2612 12440202301 14774 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * Author: * Tanuki Software Development Team */ #ifndef _LOGGER_FILE_H #define _LOGGER_FILE_H #ifdef WIN32 #include #endif #include "wrapper_i18n.h" /*#define LOGGER_FILE_DEBUG*/ #define LOGGER_FILE_SORT_MODE_TIMES 100 #define LOGGER_FILE_SORT_MODE_NAMES_ASC 101 #define LOGGER_FILE_SORT_MODE_NAMES_DEC 102 /** * Returns a valid sort mode given a name: "TIMES", "NAMES_ASC", "NAMES_DEC". * In the event of an invalid value, TIMES will be returned. */ extern int loggerFileGetSortMode(const TCHAR *modeName); /** * Returns a NULL terminated list of file names within the specified pattern. * The files will be sorted new to old for TIMES. Then incremental ordering * for NAMES. The numeric components of the names will be treated as * numbers and sorted accordingly. */ extern TCHAR** loggerFileGetFiles(const TCHAR* pattern, int sortMode); /** * Frees the array of file names returned by wrapperFileGetFiles() */ extern void loggerFileFreeFiles(TCHAR** files); #endif wrapper_3.5.26_src/src/c/loggerjni.c100644 0 0 6721 12440202301 14476 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #include #include #ifdef WIN32 #include #include #else #include #endif #include #include "loggerjni.h" void outOfMemory(const TCHAR *context, int id) { _tprintf(TEXT("WrapperJNI Error: Out of memory (%s%02d). %s\n"), context, id, getLastErrorText());fflush(NULL); } void invalidMultiByteSequence(const TCHAR *context, int id) { _tprintf(TEXT("WrapperJNI Error: Invalid multibyte Sequence found in (%s%02d). %s"), context, id, getLastErrorText());fflush(NULL); } #define LAST_ERROR_TEXT_BUFFER_SIZE 1024 /** Buffer holding the last error message. * TODO: This needs to be made thread safe, meaning that we need a buffer for each thread. */ TCHAR lastErrorTextBufferW[LAST_ERROR_TEXT_BUFFER_SIZE]; /** * Returns a textual error message of the last error encountered. * * @return The last error message. */ const TCHAR* getLastErrorText() { int errorNum; #ifdef WIN32 DWORD dwRet; TCHAR* lpszTemp = NULL; #else char* lastErrorTextMB; size_t req; #endif #ifdef WIN32 errorNum = GetLastError(); dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), LANG_NEUTRAL, (TCHAR*)&lpszTemp, 0, NULL); /* supplied buffer is not long enough */ if ((!dwRet) || ((long)LAST_ERROR_TEXT_BUFFER_SIZE - 1 < (long)dwRet + 14)) { _sntprintf(lastErrorTextBufferW, LAST_ERROR_TEXT_BUFFER_SIZE, TEXT("Error Message too large (Size %d) (Error 0x%x)"), dwRet, errorNum); } else { lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); /*remove cr and newline character */ _sntprintf(lastErrorTextBufferW, LAST_ERROR_TEXT_BUFFER_SIZE, TEXT("%s (0x%x)"), lpszTemp, errorNum); } /* following the documentation of FormatMessage, LocalFree should be called to free the output buffer. */ if (lpszTemp) { LocalFree(lpszTemp); } #else errorNum = errno; lastErrorTextMB = strerror(errorNum); req = mbstowcs(NULL, lastErrorTextMB, MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { invalidMultiByteSequence(TEXT("GLET"), 1); _sntprintf(lastErrorTextBufferW, LAST_ERROR_TEXT_BUFFER_SIZE, TEXT("Error Message could not be decoded (Error 0x%x)"), errorNum); } else if (req >= LAST_ERROR_TEXT_BUFFER_SIZE) { _sntprintf(lastErrorTextBufferW, LAST_ERROR_TEXT_BUFFER_SIZE, TEXT("Error Message too large (Size %d) (Error 0x%x)"), req, errorNum); } else { mbstowcs(lastErrorTextBufferW, lastErrorTextMB, LAST_ERROR_TEXT_BUFFER_SIZE); } #endif /* Always reterminate the buffer just to be sure it is safe because badly encoded characters can cause issues. */ lastErrorTextBufferW[LAST_ERROR_TEXT_BUFFER_SIZE - 1] = TEXT('\0'); return lastErrorTextBufferW; } /** * Returns the last error number. * * @return The last error number. */ int getLastError() { #ifdef WIN32 return GetLastError(); #else return errno; #endif } wrapper_3.5.26_src/src/c/loggerjni.h100644 0 0 705 12440202301 14457 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #ifndef _LOGGERJNI_H #define _LOGGERJNI_H #include "logger_base.h" #endif wrapper_3.5.26_src/src/c/messages.h100644 0 0 4732 12440202301 14332 0ustar 0 0 // // Values are 32 bit values layed out as follows: // // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 // +---+-+-+-----------------------+-------------------------------+ // |Sev|C|R| Facility | Code | // +---+-+-+-----------------------+-------------------------------+ // // where // // Sev - is the severity code // // 00 - Success // 01 - Informational // 10 - Warning // 11 - Error // // C - is the Customer code flag // // R - is a reserved bit // // Facility - is the facility code // // Code - is the facility's status code // // // Define the facility codes // // // Define the severity codes // // // MessageId: MSG_EVENT_LOG_MESSAGE // // MessageText: // // %2 // #define MSG_EVENT_LOG_MESSAGE 0x00000064L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM1 // // MessageText: // // jvm1 // #define MSG_EVENT_LOG_CATEGORY_JVM1 0x00000001L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM2 // // MessageText: // // jvm2 // #define MSG_EVENT_LOG_CATEGORY_JVM2 0x00000002L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM3 // // MessageText: // // jvm3 // #define MSG_EVENT_LOG_CATEGORY_JVM3 0x00000003L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM4 // // MessageText: // // jvm4 // #define MSG_EVENT_LOG_CATEGORY_JVM4 0x00000004L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM5 // // MessageText: // // jvm5 // #define MSG_EVENT_LOG_CATEGORY_JVM5 0x00000005L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM6 // // MessageText: // // jvm6 // #define MSG_EVENT_LOG_CATEGORY_JVM6 0x00000006L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM7 // // MessageText: // // jvm7 // #define MSG_EVENT_LOG_CATEGORY_JVM7 0x00000007L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM8 // // MessageText: // // jvm8 // #define MSG_EVENT_LOG_CATEGORY_JVM8 0x00000008L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVM9 // // MessageText: // // jvm9 // #define MSG_EVENT_LOG_CATEGORY_JVM9 0x00000009L // // MessageId: MSG_EVENT_LOG_CATEGORY_JVMXX // // MessageText: // // jvmxx // #define MSG_EVENT_LOG_CATEGORY_JVMXX 0x0000000AL // // MessageId: MSG_EVENT_LOG_CATEGORY_WRAPPER // // MessageText: // // wrapper // #define MSG_EVENT_LOG_CATEGORY_WRAPPER 0x0000000BL // // MessageId: MSG_EVENT_LOG_CATEGORY_PROTOCOL // // MessageText: // // wrapperp // #define MSG_EVENT_LOG_CATEGORY_PROTOCOL 0x0000000CL wrapper_3.5.26_src/src/c/org_tanukisoftware_wrapper_WrapperManager.h100644 0 0 44264 12440202301 23217 0ustar 0 0 /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class org_tanukisoftware_wrapper_WrapperManager */ #ifndef _Included_org_tanukisoftware_wrapper_WrapperManager #define _Included_org_tanukisoftware_wrapper_WrapperManager #ifdef __cplusplus extern "C" { #endif #undef org_tanukisoftware_wrapper_WrapperManager_DEFAULT_PORT #define org_tanukisoftware_wrapper_WrapperManager_DEFAULT_PORT 15003L #undef org_tanukisoftware_wrapper_WrapperManager_DEFAULT_CPU_TIMEOUT #define org_tanukisoftware_wrapper_WrapperManager_DEFAULT_CPU_TIMEOUT 10000L #undef org_tanukisoftware_wrapper_WrapperManager_TICK_MS #define org_tanukisoftware_wrapper_WrapperManager_TICK_MS 100L #undef org_tanukisoftware_wrapper_WrapperManager_TIMER_FAST_THRESHOLD #define org_tanukisoftware_wrapper_WrapperManager_TIMER_FAST_THRESHOLD 1728000L #undef org_tanukisoftware_wrapper_WrapperManager_TIMER_SLOW_THRESHOLD #define org_tanukisoftware_wrapper_WrapperManager_TIMER_SLOW_THRESHOLD 1728000L #undef org_tanukisoftware_wrapper_WrapperManager_BACKEND_TYPE_UNKNOWN #define org_tanukisoftware_wrapper_WrapperManager_BACKEND_TYPE_UNKNOWN 0L #undef org_tanukisoftware_wrapper_WrapperManager_BACKEND_TYPE_SOCKET_V4 #define org_tanukisoftware_wrapper_WrapperManager_BACKEND_TYPE_SOCKET_V4 1L #undef org_tanukisoftware_wrapper_WrapperManager_BACKEND_TYPE_SOCKET_V6 #define org_tanukisoftware_wrapper_WrapperManager_BACKEND_TYPE_SOCKET_V6 2L #undef org_tanukisoftware_wrapper_WrapperManager_BACKEND_TYPE_PIPE #define org_tanukisoftware_wrapper_WrapperManager_BACKEND_TYPE_PIPE 4L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_START #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_START 100L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_STOP #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_STOP 101L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_RESTART #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_RESTART 102L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_PING #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_PING 103L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_STOP_PENDING #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_STOP_PENDING 104L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_START_PENDING #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_START_PENDING 105L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_STARTED #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_STARTED 106L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_STOPPED #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_STOPPED 107L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_KEY #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_KEY 110L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_BADKEY #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_BADKEY 111L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_LOW_LOG_LEVEL #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_LOW_LOG_LEVEL 112L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_PING_TIMEOUT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_PING_TIMEOUT 113L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_SERVICE_CONTROL_CODE #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_SERVICE_CONTROL_CODE 114L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_PROPERTIES #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_PROPERTIES 115L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_LOG #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_LOG 116L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_CHILD_LAUNCH #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_CHILD_LAUNCH -124L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_CHILD_TERM #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_CHILD_TERM -123L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_LOGFILE #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_LOGFILE -122L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_CHECK_DEADLOCK #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_CHECK_DEADLOCK -121L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_DEADLOCK #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_DEADLOCK -120L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_APPEAR_ORPHAN #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_APPEAR_ORPHAN -119L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_PAUSE #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_PAUSE -118L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_RESUME #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_RESUME -117L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_GC #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_GC -116L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_FIRE_USER_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_MSG_FIRE_USER_EVENT -115L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_C_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_C_EVENT 200L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_CLOSE_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_CLOSE_EVENT 201L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_LOGOFF_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_LOGOFF_EVENT 202L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_SHUTDOWN_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_SHUTDOWN_EVENT 203L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_TERM_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_TERM_EVENT 204L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_HUP_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_HUP_EVENT 205L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_USR1_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_USR1_EVENT 206L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_USR2_EVENT #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_USR2_EVENT 207L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_DEBUG #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_DEBUG 1L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_INFO #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_INFO 2L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_STATUS #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_STATUS 3L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_WARN #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_WARN 4L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_ERROR #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_ERROR 5L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_FATAL #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_FATAL 6L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_ADVICE #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_ADVICE 7L #undef org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_NOTICE #define org_tanukisoftware_wrapper_WrapperManager_WRAPPER_LOG_LEVEL_NOTICE 8L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_START #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_START 65536L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_STOP #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_STOP 1L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_PAUSE #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_PAUSE 2L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_CONTINUE #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_CONTINUE 3L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_INTERROGATE #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_INTERROGATE 4L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_SHUTDOWN #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_SHUTDOWN 5L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_QUERYSUSPEND #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_QUERYSUSPEND 3328L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_QUERYSUSPENDFAILED #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_QUERYSUSPENDFAILED 3330L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_SUSPEND #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_SUSPEND 3332L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_RESUMECRITICAL #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_RESUMECRITICAL 3334L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_RESUMESUSPEND #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_RESUMESUSPEND 3335L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_BATTERYLOW #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_BATTERYLOW 3337L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_POWERSTATUSCHANGE #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_POWERSTATUSCHANGE 3338L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_OEMEVENT #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_OEMEVENT 3339L #undef org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_RESUMEAUTOMATIC #define org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_POWEREVENT_RESUMEAUTOMATIC 3346L /* Inaccessible static: m_out */ /* Inaccessible static: m_err */ /* Inaccessible static: m_outInfo */ /* Inaccessible static: m_outError */ /* Inaccessible static: m_outDebug */ /* Inaccessible static: m_windows */ /* Inaccessible static: m_macosx */ /* Inaccessible static: m_securityManagerChecked */ /* Inaccessible static: m_disposed */ /* Inaccessible static: m_starting */ /* Inaccessible static: m_started */ /* Inaccessible static: m_instance */ /* Inaccessible static: m_hook */ /* Inaccessible static: m_hookTriggered */ /* Inaccessible static: m_hookRemoveFailed */ /* Inaccessible static: m_shutdownJVMComplete */ /* Inaccessible static: m_shutdownLockMap */ /* Inaccessible static: m_shutdownLocks */ /* Inaccessible static: m_runningExecs */ /* Inaccessible static: m_args */ /* Inaccessible static: m_backendType */ /* Inaccessible static: m_backendConnected */ /* Inaccessible static: m_backendOS */ /* Inaccessible static: m_backendIS */ /* Inaccessible static: m_port */ /* Inaccessible static: m_jvmPort */ /* Inaccessible static: m_jvmPortMin */ /* Inaccessible static: m_jvmPortMax */ /* Inaccessible static: m_wrapperPortAddress */ /* Inaccessible static: m_key */ /* Inaccessible static: m_soTimeout */ /* Inaccessible static: m_cpuTimeout */ /* Inaccessible static: m_startedTicks */ /* Inaccessible static: m_lowLogLevel */ /* Inaccessible static: m_ignoreSignals */ /* Inaccessible static: m_detachStarted */ /* Inaccessible static: m_commRunner */ /* Inaccessible static: m_commRunnerStarted */ /* Inaccessible static: m_eventRunner */ /* Inaccessible static: m_eventRunnerTicks */ /* Inaccessible static: m_startupRunner */ /* Inaccessible static: m_useSystemTime */ /* Inaccessible static: m_timerFastThreshold */ /* Inaccessible static: m_timerSlowThreshold */ /* Inaccessible static: m_disableTests */ /* Inaccessible static: m_listenerForceStop */ /* Inaccessible static: m_jvmBits */ /* Inaccessible static: m_ticks */ /* Inaccessible static: m_listener */ /* Inaccessible static: m_lastPingTicks */ /* Inaccessible static: m_backendSocket */ /* Inaccessible static: m_appearHung */ /* Inaccessible static: m_slowSeconds */ /* Inaccessible static: m_ignoreUserLogoffs */ /* Inaccessible static: m_service */ /* Inaccessible static: m_debug */ /* Inaccessible static: m_logFinalizer */ /* Inaccessible static: m_jvmId */ /* Inaccessible static: m_stoppingInit */ /* Inaccessible static: m_stopping */ /* Inaccessible static: m_stoppingThread */ /* Inaccessible static: m_stopped */ /* Inaccessible static: m_pendingStopMessage */ /* Inaccessible static: m_exitCode */ /* Inaccessible static: m_libraryOK */ /* Inaccessible static: m_commandBuffer */ /* Inaccessible static: m_logFile */ /* Inaccessible static: m_properties */ /* Inaccessible static: m_wrapperEventListenerMaskList */ /* Inaccessible static: m_wrapperEventListenerMasks */ /* Inaccessible static: m_produceCoreEvents */ /* Inaccessible static: m_res */ /* Inaccessible static: m_professionalEdition */ /* Inaccessible static: m_standardEdition */ /* Inaccessible static: PROPERTY_SEPARATOR */ /* Inaccessible static: m_backendReadBuffer */ /* Inaccessible static: class_00024org_00024tanukisoftware_00024wrapper_00024WrapperManager */ /* Inaccessible static: class_00024java_00024lang_00024String */ /* Inaccessible static: class_00024java_00024lang_00024Object */ /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeInit * Signature: (Z)V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeInit (JNIEnv *, jclass, jboolean); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetLibraryVersion * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetLibraryVersion (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetJavaPID * Signature: ()I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetJavaPID (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeIsProfessionalEdition * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeIsProfessionalEdition (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeIsStandardEdition * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeIsStandardEdition (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetControlEvent * Signature: ()I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetControlEvent (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeRedirectPipes * Signature: ()I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeRedirectPipes (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeRequestThreadDump * Signature: ()V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeRequestThreadDump (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: accessViolationInner * Signature: ()V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_accessViolationInner (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeSetConsoleTitle * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeSetConsoleTitle (JNIEnv *, jclass, jstring); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetUser * Signature: (Z)Lorg/tanukisoftware/wrapper/WrapperUser; */ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetUser (JNIEnv *, jclass, jboolean); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetInteractiveUser * Signature: (Z)Lorg/tanukisoftware/wrapper/WrapperUser; */ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetInteractiveUser (JNIEnv *, jclass, jboolean); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeListServices * Signature: ()[Lorg/tanukisoftware/wrapper/WrapperWin32Service; */ JNIEXPORT jobjectArray JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeListServices (JNIEnv *, jclass); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeSendServiceControlCode * Signature: (Ljava/lang/String;I)Lorg/tanukisoftware/wrapper/WrapperWin32Service; */ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeSendServiceControlCode (JNIEnv *, jclass, jstring, jint); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeExec * Signature: ([Ljava/lang/String;Ljava/lang/String;Lorg/tanukisoftware/wrapper/WrapperProcessConfig;Z)Lorg/tanukisoftware/wrapper/WrapperProcess; */ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeExec (JNIEnv *, jclass, jobjectArray, jstring, jobject, jboolean); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeWrapperGetEnv * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeWrapperGetEnv (JNIEnv *, jclass, jstring); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeLoadWrapperResources * Signature: (Ljava/lang/String;Ljava/lang/String;Z)Lorg/tanukisoftware/wrapper/WrapperResources; */ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeLoadWrapperResources (JNIEnv *, jclass, jstring, jstring, jboolean); /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeCheckDeadLocks * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeCheckDeadLocks (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif wrapper_3.5.26_src/src/c/org_tanukisoftware_wrapper_WrapperProcessConfig.h100644 0 0 2553 12440202301 24364 0ustar 0 0 /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class org_tanukisoftware_wrapper_WrapperProcessConfig */ #ifndef _Included_org_tanukisoftware_wrapper_WrapperProcessConfig #define _Included_org_tanukisoftware_wrapper_WrapperProcessConfig #ifdef __cplusplus extern "C" { #endif #undef org_tanukisoftware_wrapper_WrapperProcessConfig_POSIX_SPAWN #define org_tanukisoftware_wrapper_WrapperProcessConfig_POSIX_SPAWN 1L #undef org_tanukisoftware_wrapper_WrapperProcessConfig_FORK_EXEC #define org_tanukisoftware_wrapper_WrapperProcessConfig_FORK_EXEC 2L #undef org_tanukisoftware_wrapper_WrapperProcessConfig_VFORK_EXEC #define org_tanukisoftware_wrapper_WrapperProcessConfig_VFORK_EXEC 3L #undef org_tanukisoftware_wrapper_WrapperProcessConfig_DYNAMIC #define org_tanukisoftware_wrapper_WrapperProcessConfig_DYNAMIC 4L /* * Class: org_tanukisoftware_wrapper_WrapperProcessConfig * Method: nativeGetEnv * Signature: ()[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_org_tanukisoftware_wrapper_WrapperProcessConfig_nativeGetEnv (JNIEnv *, jobject); /* * Class: org_tanukisoftware_wrapper_WrapperProcessConfig * Method: isSupportedNative * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_org_tanukisoftware_wrapper_WrapperProcessConfig_isSupportedNative (JNIEnv *, jclass, jint); #ifdef __cplusplus } #endif #endif wrapper_3.5.26_src/src/c/org_tanukisoftware_wrapper_WrapperProcessInputStream.h100644 0 0 2444 12440202301 25431 0ustar 0 0 /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class org_tanukisoftware_wrapper_WrapperProcessInputStream */ #ifndef _Included_org_tanukisoftware_wrapper_WrapperProcessInputStream #define _Included_org_tanukisoftware_wrapper_WrapperProcessInputStream #ifdef __cplusplus extern "C" { #endif #undef org_tanukisoftware_wrapper_WrapperProcessInputStream_SKIP_BUFFER_SIZE #define org_tanukisoftware_wrapper_WrapperProcessInputStream_SKIP_BUFFER_SIZE 2048L /* Inaccessible static: skipBuffer */ /* * Class: org_tanukisoftware_wrapper_WrapperProcessInputStream * Method: nativeRead * Signature: (Z)I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperProcessInputStream_nativeRead (JNIEnv *, jobject, jboolean); /* * Class: org_tanukisoftware_wrapper_WrapperProcessInputStream * Method: nativeClose * Signature: ()V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperProcessInputStream_nativeClose (JNIEnv *, jobject); /* * Class: org_tanukisoftware_wrapper_WrapperProcessInputStream * Method: nativeRead2 * Signature: ([BIIZ)I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperProcessInputStream_nativeRead2 (JNIEnv *, jobject, jbyteArray, jint, jint, jboolean); #ifdef __cplusplus } #endif #endif wrapper_3.5.26_src/src/c/org_tanukisoftware_wrapper_WrapperProcessOutputStream.h100644 0 0 1520 12440202301 25624 0ustar 0 0 /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class org_tanukisoftware_wrapper_WrapperProcessOutputStream */ #ifndef _Included_org_tanukisoftware_wrapper_WrapperProcessOutputStream #define _Included_org_tanukisoftware_wrapper_WrapperProcessOutputStream #ifdef __cplusplus extern "C" { #endif /* * Class: org_tanukisoftware_wrapper_WrapperProcessOutputStream * Method: nativeWrite * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperProcessOutputStream_nativeWrite (JNIEnv *, jobject, jint); /* * Class: org_tanukisoftware_wrapper_WrapperProcessOutputStream * Method: nativeClose * Signature: ()V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperProcessOutputStream_nativeClose (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif wrapper_3.5.26_src/src/c/org_tanukisoftware_wrapper_WrapperResources.h100644 0 0 2107 12440202301 23565 0ustar 0 0 /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class org_tanukisoftware_wrapper_WrapperResources */ #ifndef _Included_org_tanukisoftware_wrapper_WrapperResources #define _Included_org_tanukisoftware_wrapper_WrapperResources #ifdef __cplusplus extern "C" { #endif /* Inaccessible static: m_outError */ /* Inaccessible static: m_validateResourceKeys */ /* Inaccessible static: EMPTY_OBJECT_ARRAY */ /* Inaccessible static: class_00024org_00024tanukisoftware_00024wrapper_00024WrapperResources */ /* * Class: org_tanukisoftware_wrapper_WrapperResources * Method: nativeGetLocalizedString * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_org_tanukisoftware_wrapper_WrapperResources_nativeGetLocalizedString (JNIEnv *, jobject, jstring); /* * Class: org_tanukisoftware_wrapper_WrapperResources * Method: nativeDestroyResource * Signature: ()V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperResources_nativeDestroyResource (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif wrapper_3.5.26_src/src/c/property.c100644 0 0 202226 12440202301 14440 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.comment * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ #if defined(MACOSX) || defined(FREEBSD) #else #include #endif #include #include #include #include #ifdef WIN32 #include /* MS Visual Studio 8 went and deprecated the POXIX names for functions. * Fixing them all would be a big headache for UNIX versions. */ #pragma warning(disable : 4996) #else #include #include #include #include #endif #include "wrapper_i18n.h" #include "logger.h" #include "property.h" #include "wrapper.h" #include "wrapper_file.h" #define MAX_INCLUDE_DEPTH 10 /* The largest possible "name+'='+value" property pair length on Windows. */ #define MAX_ENV_PAIR_LEN 32767 EnvSrc *baseEnvSrc = NULL; /** Stores the time that the property file began to be loaded. */ struct tm loadPropertiesTM; const TCHAR **escapedPropertyNames = NULL; void setInnerProperty(Properties *properties, Property *property, const TCHAR *propertyValue, int warnUndefinedVars); /** * @param warnUndefinedVars Log warnings about missing environment variables. */ void prepareProperty(Properties *properties, Property *property, int warnUndefinedVars) { TCHAR *oldValue; if (_tcsstr(property->value, TEXT("%"))) { /* Reset the property. If the unreplaced environment variables are now available * setting it again will cause it to be replaced correctly. If not this will * only waste time. The value will be freed in the process so we need to * keep it around. */ #ifdef _DEBUG _tprintf( TEXT("Unreplaced property %s=%s\n"), property->name, property->value ); #endif oldValue = malloc(sizeof(TCHAR) * (_tcslen(property->value) + 1)); if (!oldValue) { outOfMemory(TEXT("PP"), 1); } else { _tcsncpy(oldValue, property->value, _tcslen(property->value) + 1); setInnerProperty(properties, property, oldValue, warnUndefinedVars); free(oldValue); } #ifdef _DEBUG _tprintf( TEXT(" -> property %s=%s\n"), property->name, property->value ); #endif } } /** * Private function to find a Property structure. */ Property* getInnerProperty(Properties *properties, const TCHAR *propertyName, int warnUndefinedVars) { Property *property; int cmp; /* Loop over the properties which are in order and look for the specified property. */ property = properties->first; while (property != NULL) { cmp = strcmpIgnoreCase(property->name, propertyName); if (cmp > 0) { /* This property would be after the one being looked for, so it does not exist. */ return NULL; } else if (cmp == 0) { /* We found it. */ prepareProperty(properties, property, warnUndefinedVars && properties->logWarnings); return property; } /* Keep looking */ property = property->next; } /* We did not find the property being looked for. */ return NULL; } void insertInnerProperty(Properties *properties, Property *newProperty) { Property *property; int cmp; /* Loop over the properties which are in order and look for the specified property. */ /* This function assumes that Property is not already in properties. */ property = properties->first; while (property != NULL) { cmp = strcmpIgnoreCase(property->name, newProperty->name); if (cmp > 0) { /* This property would be after the new property, so insert it here. */ newProperty->previous = property->previous; newProperty->next = property; if (property->previous == NULL) { /* This was the first property */ properties->first = newProperty; } else { property->previous->next = newProperty; } property->previous = newProperty; /* We are done, so return */ return; } property = property->next; } /* The new property needs to be added at the end */ newProperty->previous = properties->last; if (properties->last == NULL) { /* This will be the first property. */ properties->first = newProperty; } else { /* Point the old last property to the new last property. */ properties->last->next = newProperty; } properties->last = newProperty; newProperty->next = NULL; } Property* createInnerProperty() { Property *property; property = malloc(sizeof(Property)); if (!property) { outOfMemory(TEXT("CIP"), 1); return NULL; } property->name = NULL; property->next = NULL; property->previous = NULL; property->value = NULL; return property; } /** * Private function to dispose a Property structure. Assumes that the * Property is disconnected already. */ void disposeInnerProperty(Property *property) { if (property->name) { free(property->name); } if (property->value) { free(property->value); } free(property); } TCHAR generateValueBuffer[256]; /** * This function returns a reference to a static buffer and is NOT thread safe. * It is currently called only when loading a property file and when firing an event. * Both happen in the main thread. * The largest return value can be 15+1 characters. */ TCHAR* generateTimeValue(const TCHAR* format, struct tm *timeTM) { if (strcmpIgnoreCase(format, TEXT("YYYYMMDDHHIISS")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%04d%02d%02d%02d%02d%02d"), timeTM->tm_year + 1900, timeTM->tm_mon + 1, timeTM->tm_mday, timeTM->tm_hour, timeTM->tm_min, timeTM->tm_sec ); } else if (strcmpIgnoreCase(format, TEXT("YYYYMMDD_HHIISS")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%04d%02d%02d_%02d%02d%02d"), timeTM->tm_year + 1900, timeTM->tm_mon + 1, timeTM->tm_mday, timeTM->tm_hour, timeTM->tm_min, timeTM->tm_sec ); } else if (strcmpIgnoreCase(format, TEXT("YYYYMMDDHHII")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%04d%02d%02d%02d%02d"), timeTM->tm_year + 1900, timeTM->tm_mon + 1, timeTM->tm_mday, timeTM->tm_hour, timeTM->tm_min ); } else if (strcmpIgnoreCase(format, TEXT("YYYYMMDDHH")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%04d%02d%02d%02d"), timeTM->tm_year + 1900, timeTM->tm_mon + 1, timeTM->tm_mday, timeTM->tm_hour ); } else if (strcmpIgnoreCase(format, TEXT("YYYYMMDD")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%04d%02d%02d"), timeTM->tm_year + 1900, timeTM->tm_mon + 1, timeTM->tm_mday); } else { _sntprintf(generateValueBuffer, 256, TEXT("{INVALID}")); } return generateValueBuffer; } /** * This function returns a reference to a static buffer and is NOT thread safe. * It is currently called only when loading a property file and when firing an event. * Both happen in the main thread. * The largest return value can be 9+1 characters. */ TCHAR* generateRandValue(const TCHAR* format) { if (strcmpIgnoreCase(format, TEXT("N")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%01d"), rand() % 10); } else if (strcmpIgnoreCase(format, TEXT("NN")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%02d"), rand() % 100); } else if (strcmpIgnoreCase(format, TEXT("NNN")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%03d"), rand() % 1000); } else if (strcmpIgnoreCase(format, TEXT("NNNN")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%04d"), rand() % 10000); } else if (strcmpIgnoreCase(format, TEXT("NNNNN")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%04d%01d"), rand() % 10000, rand() % 10); } else if (strcmpIgnoreCase(format, TEXT("NNNNNN")) == 0) { _sntprintf(generateValueBuffer, 256, TEXT("%04d%02d"), rand() % 10000, rand() % 100); } else { _sntprintf(generateValueBuffer, 256, TEXT("{INVALID}")); } return generateValueBuffer; } /** * Parses a property value and populates any environment variables. If the expanded * environment variable would result in a string that is longer than bufferLength * the value is truncated. * * @param warnUndefinedVars Log warnings about missing environment variables. * @param warnedUndefVarMap Map of variables which have previously been logged, may be NULL if warnUndefinedVars false. * @param warnLogLevel Log level at which any warnings will be logged. */ void evaluateEnvironmentVariables(const TCHAR *propertyValue, TCHAR *buffer, int bufferLength, int warnUndefinedVars, PHashMap warnedUndefVarMap, int warnLogLevel) { const TCHAR *in; TCHAR *out; TCHAR *envName; TCHAR *envValue; int envValueNeedFree; TCHAR *start; TCHAR *end; size_t len; size_t outLen; size_t bufferAvailable; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("evaluateEnvironmentVariables(properties, '%s', buffer, %d, %d)"), propertyValue, bufferLength, warnUndefinedVars); #endif buffer[0] = TEXT('\0'); in = propertyValue; out = buffer; bufferAvailable = bufferLength - 1; /* Reserver room for the null terminator */ /* Loop until we hit the end of string. */ while (in[0] != TEXT('\0')) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" initial='%s', buffer='%s'"), propertyValue, buffer); #endif start = _tcschr(in, TEXT('%')); if (start != NULL) { end = _tcschr(start + 1, TEXT('%')); if (end != NULL) { /* A pair of '%' characters was found. An environment */ /* variable name should be between the two. */ len = (int)(end - start - 1); envName = malloc(sizeof(TCHAR) * (len + 1)); if (envName == NULL) { outOfMemory(TEXT("EEV"), 1); return; } _tcsncpy(envName, start + 1, len); envName[len] = TEXT('\0'); /* See if it is a special dynamic environment variable */ envValueNeedFree = FALSE; if (_tcsstr(envName, TEXT("WRAPPER_TIME_")) == envName) { /* Found a time value. */ envValue = generateTimeValue(envName + 13, &loadPropertiesTM); } else if (_tcsstr(envName, TEXT("WRAPPER_RAND_")) == envName) { /* Found a time value. */ envValue = generateRandValue(envName + 13); } else { /* Try looking up the environment variable. */ envValue = _tgetenv(envName); #if !defined(WIN32) && defined(UNICODE) envValueNeedFree = TRUE; #endif } if (envValue != NULL) { /* An envvar value was found. */ /* Copy over any text before the envvar */ outLen = (int)(start - in); if (bufferAvailable < outLen) { outLen = bufferAvailable; } if (outLen > 0) { _tcsncpy(out, in, outLen); out += outLen; bufferAvailable -= outLen; } /* Copy over the env value */ outLen = _tcslen(envValue); if (bufferAvailable < outLen) { outLen = bufferAvailable; } if (outLen > 0) { _tcsncpy(out, envValue, outLen); out += outLen; bufferAvailable -= outLen; } if (envValueNeedFree) { free(envValue); } /* Terminate the string */ out[0] = TEXT('\0'); /* Set the new in pointer */ in = end + 1; } else { /* Not found. So copy over the input up until the */ /* second '%'. Leave it in case it is actually the */ /* start of an environment variable name */ outLen = len = end - in + 1; if (bufferAvailable < outLen) { outLen = bufferAvailable; } if (outLen > 0) { _tcsncpy(out, in, outLen); out += outLen; bufferAvailable -= outLen; } in += len; /* Terminate the string */ out[0] = TEXT('\0'); if (warnUndefinedVars) { if (hashMapGetKWVW(warnedUndefVarMap, envName) == NULL) { /* This is the first time this environment variable was noticed, so report it to the user then remember so we don't report it again. */ log_printf(WRAPPER_SOURCE_WRAPPER, warnLogLevel, TEXT("The '%s' environment variable was referenced but has not been defined."), envName); hashMapPutKWVW(warnedUndefVarMap, envName, envName); } } } free(envName); } else { /* Only a single '%' TCHAR was found. Leave it as is. */ outLen = len = _tcslen(in); if (bufferAvailable < outLen) { outLen = bufferAvailable; } if (outLen > 0) { _tcsncpy(out, in, outLen); out += outLen; bufferAvailable -= outLen; } in += len; /* Terminate the string */ out[0] = TEXT('\0'); } } else { /* No more '%' chars in the string. Copy over the rest. */ outLen = len = _tcslen(in); if (bufferAvailable < outLen) { outLen = bufferAvailable; } if (outLen > 0) { _tcsncpy(out, in, outLen); out += outLen; bufferAvailable -= outLen; } in += len; /* Terminate the string */ out[0] = TEXT('\0'); } } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" final buffer='%s'"), buffer); #endif } /** * * @param warnUndefinedVars Log warnings about missing environment variables. */ void setInnerProperty(Properties *properties, Property *property, const TCHAR *propertyValue, int warnUndefinedVars) { int i, count; /* The property value is expanded into a large buffer once, but that is temporary. The actual * value is stored in the minimum required size. */ TCHAR *buffer; /* Free any existing value */ if (property->value != NULL) { free(property->value); property->value = NULL; } /* Set the new value using a copy of the provided value. */ if (propertyValue == NULL) { property->value = NULL; } else { buffer = malloc(MAX_PROPERTY_VALUE_LENGTH * sizeof(TCHAR)); if (buffer) { evaluateEnvironmentVariables(propertyValue, buffer, MAX_PROPERTY_VALUE_LENGTH, warnUndefinedVars, properties->warnedVarMap, properties->logWarningLogLevel); property->value = malloc(sizeof(TCHAR) * (_tcslen(buffer) + 1)); if (!property->value) { outOfMemoryQueued(TEXT("SIP"), 1); } else { /* Strip any non valid characters like control characters. Some valid characters are * less than 0 when the TCHAR is unsigned. */ for (i = 0, count = 0; i < (int)_tcslen(buffer); i++) { /* Only add valid characters, skipping any control characters EXCEPT for a line feed. */ if ((buffer[i] == TEXT('\n')) || (!_istcntrl(buffer[i]))) { property->value[count++] = buffer[i]; } } /* Crop string to new size */ property->value[count] = TEXT('\0'); } free(buffer); } else { outOfMemoryQueued(TEXT("SIP"), 2); } } } static int loadPropertiesCallback(void *callbackParam, const TCHAR *fileName, int lineNumber, TCHAR *config, int debugProperties) { Properties *properties = (Properties *)callbackParam; TCHAR *d; properties->debugProperties = debugProperties; if (_tcsstr(config, TEXT("include")) == config) { /* Users sometimes remove the '#' from include statements. Add a warning to help them notice the problem. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Include file reference missing leading '#': %s"), config); } else if ((d = _tcschr(config, TEXT('='))) != NULL) { /* Locate the first '=' in the line, ignore lines that do not contain a '=' */ /* Null terminate the first half of the line. */ *d = TEXT('\0'); d++; addProperty(properties, fileName, lineNumber, config, d, FALSE, FALSE, TRUE, FALSE); } return TRUE; } /** * Create a Properties structure loaded in from the specified file. * Must call disposeProperties to free up allocated memory. * * @param properties Properties structure to load into. * @param filename File to load the properties from. * @param preload TRUE if this is a preload call that should have supressed error output. * @param argCommand Argument passed to the binary. * @param originalWorkingDir Working directory of the binary at the moment it was launched. * @param isDebugging Flag that controls whether or not debug output will be logged. * * @return TRUE if there were any problems, FALSE if successful. */ int loadProperties(Properties *properties, const TCHAR* filename, int preload, const TCHAR *argCommand, const TCHAR *originalWorkingDir, int isDebugging) { /* Store the time that the property file began to be loaded. */ #ifdef WIN32 struct _timeb timebNow; #else struct timeval timevalNow; #endif time_t now; struct tm *nowTM; int loadResult; #ifdef WIN32 _ftime(&timebNow); now = (time_t)timebNow.time; #else gettimeofday(&timevalNow, NULL); now = (time_t)timevalNow.tv_sec; #endif nowTM = localtime(&now); memcpy(&loadPropertiesTM, nowTM, sizeof(struct tm)); loadResult = configFileReader(filename, FALSE, loadPropertiesCallback, properties, TRUE, preload, argCommand, originalWorkingDir, properties->warnedVarMap, properties->logWarnings, properties->logWarningLogLevel, isDebugging); /* Any failure is a failure in the root. */ switch (loadResult) { case CONFIG_FILE_READER_SUCCESS: return FALSE; case CONFIG_FILE_READER_FAIL: case CONFIG_FILE_READER_HARD_FAIL: return TRUE; default: _tprintf(TEXT("Unexpected load error %d\n"), loadResult); return TRUE; } } Properties* createProperties() { Properties *properties = malloc(sizeof(Properties)); if (!properties) { outOfMemory(TEXT("CP"), 1); return NULL; } properties->debugProperties = FALSE; properties->logWarnings = TRUE; properties->logWarningLogLevel = LEVEL_WARN; properties->first = NULL; properties->last = NULL; properties->warnedVarMap = newHashMap(8); if (!properties->warnedVarMap) { disposeProperties(properties); return NULL; } return properties; } void disposeProperties(Properties *properties) { /* Loop and dispose any Property structures */ Property *tempProperty; Property *property; if (properties) { property = properties->first; properties->first = NULL; properties->last = NULL; while (property != NULL) { /* Save the next property */ tempProperty = property->next; /* Clean up the current property */ disposeInnerProperty(property); property = NULL; /* set the current property to the next. */ property = tempProperty; } if (properties->warnedVarMap) { freeHashMap(properties->warnedVarMap); } /* Dispose the Properties structure */ free(properties); properties = NULL; } } /** * This method cleans the environment at shutdown. */ void disposeEnvironment() { EnvSrc *current, *previous; if (baseEnvSrc) { current = baseEnvSrc; while (current != NULL) { free(current->name); previous = current; current = current->next; free(previous); } baseEnvSrc = NULL; } } void removeProperty(Properties *properties, const TCHAR *propertyName) { Property *property; Property *next; Property *previous; /* Look up the property */ property = getInnerProperty(properties, propertyName, FALSE); if (property == NULL) { /* The property did not exist, so nothing to do. */ } else { next = property->next; previous = property->previous; /* Disconnect the property */ if (next == NULL) { /* This was the last property */ properties->last = previous; } else { next->previous = property->previous; } if (previous == NULL) { /* This was the first property */ properties->first = next; } else { previous->next = property->next; } /* Now that property is disconnected, if can be disposed. */ disposeInnerProperty(property); } } /** * Sets an environment variable with the specified value. * The function will only set the variable if its value is changed, but if * it does, the call will result in a memory leak the size of the string: * "name=value". * * For Windows, the putenv_s funcion looks better, but it is not available * on some older SDKs and non-pro versions of XP. * * @param name Name of the variable being set. * @param value Value to be set, NULL to clear it. * * Return TRUE if there were any problems, FALSE otherwise. */ int setEnvInner(const TCHAR *name, const TCHAR *value) { int result = FALSE; TCHAR *oldVal; #ifdef WIN32 #if !defined(WRAPPER_USE_PUTENV_S) size_t len; TCHAR *envBuf; #endif #endif #if defined(WRAPPER_USE_PUTENV) size_t len; TCHAR *envBuf; #endif /* Get the current environment variable value so we can avoid allocating and * setting the variable if it has not changed its value. */ oldVal = _tgetenv(name); if (value == NULL) { /*_tprintf("clear %s=\n", name);*/ /* Only clear the variable if it is actually set to avoid unnecessary leaks. */ if (oldVal != NULL) { #ifdef WIN32 #if defined(WRAPPER_USE_PUTENV_S) if (_tputenv_s(name, TEXT("")) == EINVAL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to clear the '%s' environment variable."), name); result = TRUE; } #else len = _tcslen(name) + 1 + 1; envBuf = malloc(sizeof(TCHAR) * len); if (!envBuf) { outOfMemory(TEXT("SEI"), 1); result = TRUE; } else { _sntprintf(envBuf, len, TEXT("%s="), name); /* The memory pointed to by envBuf should only be freed if this is UNICODE. */ if (_tputenv(envBuf)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to clear the '%s' environment variable."), name); result = TRUE; } } #endif #else #if defined(WRAPPER_USE_PUTENV) len = _tcslen(name) + 1 + 1; envBuf = malloc(sizeof(TCHAR) * len); if (!envBuf) { outOfMemory(TEXT("SEI"), 1); result = TRUE; } else { _sntprintf(envBuf, len, TEXT("%s="), name); /* The memory pointed to by envBuf should only be freed if this is UNICODE. */ if (_tputenv(envBuf)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to clear the '%s' environment variable."), name); result = TRUE; } #ifdef UNICODE free(envBuf); #endif } #else _tunsetenv(name); #endif #endif } } else { /*_tprintf("set %s=%s\n", name, value);*/ if ((oldVal == NULL) || (_tcscmp(oldVal, value) != 0)) { #ifdef WIN32 #if defined(WRAPPER_USE_PUTENV_S) if (_tputenv_s(name, value) == EINVAL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to set '%s% environment variable to: %s"), name, value); result = TRUE; } #else len = _tcslen(name) + 1 + _tcslen(value) + 1; if (len > MAX_ENV_PAIR_LEN) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to set the '%s' environment variable because total pair length of %d is longer than maximum for the OS of %d."), name, len, MAX_ENV_PAIR_LEN); result = TRUE; } else { envBuf = malloc(sizeof(TCHAR) * len); if (!envBuf) { outOfMemory(TEXT("SEI"), 2); result = TRUE; } else { _sntprintf(envBuf, len, TEXT("%s=%s"), name, value); /* The memory pointed to by envBuf should only be freed if this is UNICODE. */ if (_tputenv(envBuf)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to set environment variable: %s=%s"), name, value); result = TRUE; } } } #endif #else #if defined(WRAPPER_USE_PUTENV) len = _tcslen(name) + 1 + _tcslen(value) + 1; envBuf = malloc(sizeof(TCHAR) * len); if (!envBuf) { outOfMemory(TEXT("SEI"), 2); result = TRUE; } else { _sntprintf(envBuf, len, TEXT("%s=%s"), name, value); /* The memory pointed to by envBuf should only be freed if this is UNICODE. */ if (_tputenv(envBuf)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to set the '%s' environment variable to: %s"), name, value); result = TRUE; } #ifdef UNICODE free(envBuf); #endif } #else if (_tsetenv(name, value, TRUE)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to set the '%s' environment variable to: %s"), name, value); result = TRUE; } #endif #endif } } #if !defined(WIN32) && defined(UNICODE) if (oldVal != NULL) { free(oldVal); } #endif return result; } /** * Sets an environment variable with the specified value. * The function will only set the variable if its value is changed, but if * it does, the call will result in a memory leak the size of the string: * "name=value". * * @param name Name of the variable being set. * @param value Value to be set, NULL to clear it. * @param source Where the variable came from. * Must be one of ENV_SOURCE_PARENT, ENV_SOURCE_APPLICATION, ENV_SOURCE_CONFIG, * or ENV_SOURCE_REG_SYSTEM or ENV_SOURCE_REG_ACCOUNT on Windows. * If value is ENV_SOURCE_PARENT then the value may be NULL and will never be * set to the environment. * * Return TRUE if there were any problems, FALSE otherwise. */ int setEnv(const TCHAR *name, const TCHAR *value, int source) { EnvSrc **thisEnvSrcRef; EnvSrc *thisEnvSrc; size_t len; TCHAR *nameCopy; EnvSrc *newEnvSrc; int cmpRes; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("setEnv(%s, %s, %d)"), name, value, source); #endif thisEnvSrcRef = &baseEnvSrc; thisEnvSrc = baseEnvSrc; /* Create a copy of the name so we can store it. */ len = _tcslen(name) + 1; nameCopy = malloc(sizeof(TCHAR) * len); if (!nameCopy) { outOfMemory(TEXT("SE"), 1); return TRUE; } _sntprintf(nameCopy, len, TEXT("%s"), name); /* Figure out where we want to set the value. */ while (thisEnvSrc) { cmpRes = strcmpIgnoreCase(thisEnvSrc->name, name); if (cmpRes == 0) { /* This is the same value. It is being changed. */ /* The nameCopy is not needed so free it up. */ free(nameCopy); thisEnvSrc->source |= source; if (source != ENV_SOURCE_PARENT) { return setEnvInner(name, value); } return FALSE; } else if (cmpRes > 0) { /* This EnvSrc would be after the one being set, so we need to insert it. */ newEnvSrc = malloc(sizeof(EnvSrc)); if (!newEnvSrc) { outOfMemory(TEXT("SEV"), 2); return TRUE; } newEnvSrc->source = source; newEnvSrc->name = nameCopy; newEnvSrc->next = thisEnvSrc; *thisEnvSrcRef = newEnvSrc; if (source != ENV_SOURCE_PARENT) { return setEnvInner(name, value); } return FALSE; } else { /* This EnvSrc would be before the one being set, so keep looking. */ thisEnvSrcRef = &(thisEnvSrc->next); thisEnvSrc = thisEnvSrc->next; } } /* If we get here then we are at the end of the list. */ thisEnvSrc = malloc(sizeof(EnvSrc)); if (!thisEnvSrc) { outOfMemory(TEXT("SEV"), 3); return TRUE; } thisEnvSrc->source = source; thisEnvSrc->name = nameCopy; thisEnvSrc->next = NULL; *thisEnvSrcRef = thisEnvSrc; if (source != ENV_SOURCE_PARENT) { return setEnvInner(name, value); } return FALSE; } /* Trims any whitespace from the beginning and end of the in string * and places the results in the out buffer. Assumes that the out * buffer is at least as large as the in buffer. */ void trim(const TCHAR *in, TCHAR *out) { size_t len; size_t first; size_t last; len = _tcslen(in); if (len > 0) { first = 0; last = len - 1; /* Right Trim */ while (((in[first] == ' ') || (in[first] == '\t')) && (first < last)) { first++; } /* Left Trim */ while ((last > first) && ((in[last] == ' ') || (in[last] == '\t'))) { last--; } /* Copy over what is left. */ len = last - first + 1; if (len > 0) { _tcsncpy(out, in + first, len); } } out[len] = TEXT('\0'); } /** * Used to set a NULL terminated list of property names whose values should be * escaped when read in from a file. '\\' will become '\' and '\n' will * become '^J', all other characters following '\' will be left as is. * * @param propertyNames NULL terminated list of property names. Property names * can contain a single '*' wildcard which will match 0 or * more characters. */ void setEscapedProperties(const TCHAR **propertyNames) { escapedPropertyNames = propertyNames; } /** * Returns true if the specified property matches one of the property names * previosly set in a call to setEscapableProperties() * * @param propertyName Property name to test. * * @return TRUE if the property should be escaped. FALSE otherwise. */ int isEscapedProperty(const TCHAR *propertyName) { size_t nameLen; size_t i; const TCHAR *pattern; TCHAR *wildPos; size_t headLen; size_t tailLen; int matched; size_t patternI; size_t nameI; if (escapedPropertyNames) { nameLen = _tcslen(propertyName); i = 0; while (escapedPropertyNames[i]) { pattern = escapedPropertyNames[i]; if (strcmpIgnoreCase(pattern, propertyName) == 0) { /* Direct Match. */ #ifdef _DEBUG _tprintf(TEXT("Property %s matched pattern %s\n"), propertyName, pattern); #endif return TRUE; } else { wildPos = _tcschr(pattern, TEXT('*')); if (wildPos) { /* The string contains a wildcard. */ /* Try to match the head of the property name. */ headLen = wildPos - pattern; if (headLen < nameLen) { matched = TRUE; patternI = 0; nameI = 0; while (patternI < headLen) { if (pattern[patternI] != propertyName[nameI]) { matched = FALSE; break; } patternI++; nameI++; } if (matched) { tailLen = _tcslen(pattern) - headLen - 1; if (tailLen < nameLen - headLen) { matched = TRUE; patternI = headLen + 1; nameI = nameLen - tailLen; while (nameI < nameLen) { if (pattern[patternI] != propertyName[nameI]) { matched = FALSE; break; } patternI++; nameI++; } if (matched) { #ifdef _DEBUG _tprintf(TEXT("Property %s matched pattern %s\n"), propertyName, pattern); #endif return TRUE; } } } } } } i++; } } return FALSE; } /** * Expands escaped characters and returns a newly malloced string with the result. * '\n' replaced with '^J' * '\\' replaced with '\' * Other escaped characters will show as is. * * @param buffer Original buffer containing escaped characters. * * @return The new expanded buffer. It is the responsibility of the caller to free memory later. */ TCHAR *expandEscapedCharacters(const TCHAR* buffer) { size_t inPos; size_t outPos; TCHAR *outBuffer; int i; TCHAR c1, c2; /* First count the length of the required output buffer to hold the current line. Use the same code twice to avoid maintenance problems. */ outBuffer = NULL; for (i = 0; i < 2; i++) { inPos = 0; outPos = 0; do { c1 = buffer[inPos]; /* The real backslash is #92. The yen mark from files loaded from ShiftJIS is #165. */ if ((c1 == TEXT('\\')) || (c1 == 165)) { /* Escape. */ c2 = buffer[inPos + 1]; if (c2 == TEXT('n')) { /* Line feed. */ inPos++; if (outBuffer) { outBuffer[outPos] = TEXT('\n'); } outPos++; } else if ((c2 == TEXT('\\')) || (c2 == 165)) { /* Back slash. */ inPos++; if (outBuffer) { outBuffer[outPos] = c1; } outPos++; } else if (c2 == 0) { /* Premature End of buffer. Show the backslash. */ if (outBuffer) { outBuffer[outPos] = c1; } outPos++; c1 = 0; } else { /* Unknown char, show the unescaped backslash. */ inPos++; if (outBuffer) { outBuffer[outPos] = c1; outBuffer[outPos + 1] = c2; } outPos += 2; } inPos++; } else if (c1 == 0) { /* End of buffer. */ } else { /* Normal character. */ if (outBuffer) { outBuffer[outPos] = c1; } outPos++; inPos++; } } while (c1 != 0); /* string terminator. */ if (outBuffer) { outBuffer[outPos] = TEXT('\0'); } outPos++; if (outBuffer) { /* We have have full outBuffer. Fall through. */ } else { /* First pass. We need to allocate the outBuffer. */ outBuffer = malloc(outPos * sizeof(TCHAR)); if (!outBuffer) { outOfMemory(TEXT("ELF"), 1); return NULL; } } } return outBuffer; } /** * Adds a single property to the properties structure. * * @param properties Properties structure to add to. * @param filename Name of the file from which the property was loaded. NULL, if not from a file. * @param lineNum Line number of the property declaration in the file. Ignored if filename is NULL. * @param propertyName Name of the new Property. * @param propertyValue Initial property value. * @param finalValue TRUE if the property should be set as static. * @param quotable TRUE if the property could contain quotes. * @param escapable TRUE if the propertyValue can be escaped if its propertyName * is in the list set with setEscapableProperties(). * @param internal TRUE if the property is a Wrapper internal property. * * @return The newly created Property, or NULL if there was a reported error. */ Property* addProperty(Properties *properties, const TCHAR* filename, int lineNum, const TCHAR *propertyName, const TCHAR *propertyValue, int finalValue, int quotable, int escapable, int internal) { int setValue; Property *property; TCHAR *oldVal; TCHAR *propertyNameTrim; TCHAR *propertyValueTrim; TCHAR *propertyExpandedValue; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("addProperty(properties, %s, '%s', '%s', %d, %d, %d, %d)"), (filename ? filename : TEXT("")), propertyName, propertyValue, finalValue, quotable, escapable, internal); #endif /* It is possible that the propertyName and or properyValue contains extra spaces. */ propertyNameTrim = malloc(sizeof(TCHAR) * (_tcslen(propertyName) + 1)); if (!propertyNameTrim) { outOfMemory(TEXT("AP"), 1); return NULL; } trim(propertyName, propertyNameTrim); propertyValueTrim = malloc(sizeof(TCHAR) * ( _tcslen(propertyValue) + 1)); if (!propertyValueTrim) { outOfMemory(TEXT("AP"), 4); free(propertyNameTrim); return NULL; } trim(propertyValue, propertyValueTrim); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" trimmed name='%s', value='%s'"), propertyNameTrim, propertyValueTrim); #endif /* See if the property already exists */ setValue = TRUE; property = getInnerProperty(properties, propertyNameTrim, FALSE); if (property == NULL) { /* This is a new property */ property = createInnerProperty(); if (!property) { free(propertyNameTrim); free(propertyValueTrim); return NULL; } /* Store a copy of the name */ property->name = malloc(sizeof(TCHAR) * (_tcslen(propertyNameTrim) + 1)); if (!property->name) { outOfMemory(TEXT("AP"), 3); disposeInnerProperty(property); free(propertyNameTrim); free(propertyValueTrim); return NULL; } _tcsncpy(property->name, propertyNameTrim, _tcslen(propertyNameTrim) + 1); /* Insert this property at the correct location. Value will still be null. */ insertInnerProperty(properties, property); } else { /* The property was already set. Only change it if non final */ if (property->internal) { setValue = FALSE; if (properties->debugProperties) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The \"%s\" property is defined by the Wrapper internally and can not be overwritten.\n Ignoring redefinition on line #%d of configuration file: %s\n Fixed Value %s=%s\n Ignored Value %s=%s"), propertyNameTrim, lineNum, (filename ? filename : TEXT("")), propertyNameTrim, property->value, propertyNameTrim, propertyValueTrim); } } else if (property->finalValue) { setValue = FALSE; if (properties->debugProperties) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The \"%s\" property was defined on the Wrapper command line and can not be overwritten.\n Ignoring redefinition on line #%d of configuration file: %s\n Fixed Value %s=%s\n Ignored Value %s=%s"), propertyNameTrim, lineNum, (filename ? filename : TEXT("")), propertyNameTrim, property->value, propertyNameTrim, propertyValueTrim); } } else { if (properties->debugProperties) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The \"%s\" property was redefined on line #%d of configuration file: %s\n Old Value %s=%s\n New Value %s=%s"), propertyNameTrim, lineNum, (filename ? filename : TEXT("")), propertyNameTrim, property->value, propertyNameTrim, propertyValueTrim); } } } free(propertyNameTrim); if (setValue) { if (escapable && isEscapedProperty(property->name)) { /* Expand the value. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("expanding value of %s"), property->name); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" value : %s"), propertyValueTrim); #endif propertyExpandedValue = expandEscapedCharacters(propertyValueTrim); if (!propertyExpandedValue) { free(propertyValueTrim); return NULL; } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" expanded: %s"), propertyExpandedValue); #endif /* Set the property value. */ setInnerProperty(properties, property, propertyExpandedValue, FALSE); free(propertyExpandedValue); } else { /* Set the property value. */ setInnerProperty(properties, property, propertyValueTrim, FALSE); } if (property->value == NULL) { free(propertyValueTrim); return NULL; } /* Store the final flag */ property->finalValue = finalValue; /* Store the quotable flag. */ property->quotable = quotable; /* Store the internal flab. */ property->internal = internal; /* Prepare the property by expanding any environment variables that are defined. */ prepareProperty(properties, property, FALSE); /* See if this is a special property */ if ((_tcslen(property->name) > 12) && (_tcsstr(property->name, TEXT("set.default.")) == property->name)) { /* This property is an environment variable definition that should only * be set if the environment variable does not already exist. Get the * value back out of the property as it may have had environment * replacements. */ oldVal = _tgetenv(property->name + 12); if (oldVal == NULL) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("set default env('%s', '%s')"), property->name + 12, property->value); #endif setEnv(property->name + 12, property->value, (internal ? ENV_SOURCE_APPLICATION : ENV_SOURCE_CONFIG)); } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT( "not setting default env('%s', '%s'), already set to '%s'"), property->name + 12, property->value, oldVal); #endif #if !defined(WIN32) && defined(UNICODE) free(oldVal); #endif } } else if ((_tcslen(property->name) > 4) && (_tcsstr(property->name, TEXT("set.")) == property->name)) { /* This property is an environment variable definition. Get the * value back out of the property as it may have had environment * replacements. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("set env('%s', '%s')"), property->name + 4, property->value); #endif setEnv(property->name + 4, property->value, (internal ? ENV_SOURCE_APPLICATION : ENV_SOURCE_CONFIG)); } } free(propertyValueTrim); return property; } /** * Takes a name/value pair in the form = and attempts to add * it to the specified properties table. * * @param properties Properties structure to add to. * @param filename Name of the file from which the property was loaded. NULL, if not from a file. * @param lineNum Line number of the property declaration in the file. Ignored if filename is NULL. * @param propertyNameValue The "name=value" pair to create the property from. * @param finalValue TRUE if the property should be set as static. * @param quotable TRUE if the property could contain quotes. * @param internal TRUE if the property is a Wrapper internal property. * * Returns 0 if successful, otherwise 1 */ int addPropertyPair(Properties *properties, const TCHAR* filename, int lineNum, const TCHAR *propertyNameValue, int finalValue, int quotable, int internal) { TCHAR buffer[MAX_PROPERTY_NAME_VALUE_LENGTH]; TCHAR *d; /* Make a copy of the pair that we can edit */ if (_tcslen(propertyNameValue) + 1 >= MAX_PROPERTY_NAME_VALUE_LENGTH) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("The following property name value pair is too large. Need to increase the internal buffer size: %s"), propertyNameValue); return 1; } _tcsncpy(buffer, propertyNameValue, MAX_PROPERTY_NAME_VALUE_LENGTH); /* Locate the first '=' in the pair */ if ((d = _tcschr(buffer, TEXT('='))) != NULL) { /* Null terminate the first half of the line. */ *d = TEXT('\0'); d++; if (addProperty(properties, filename, lineNum, buffer, d, finalValue, quotable, FALSE, internal) != NULL) { return 0; } else { return 1; } } else { return 1; } } const TCHAR* getStringProperty(Properties *properties, const TCHAR *propertyName, const TCHAR *defaultValue) { Property *property; property = getInnerProperty(properties, propertyName, TRUE); if (property == NULL) { if (defaultValue != NULL) { property = addProperty(properties, NULL, 0, propertyName, defaultValue, FALSE, FALSE, FALSE, FALSE); if (property) { return property->value; } else { /* We failed to add the property, but still return the default. */ return defaultValue; } } else { return NULL; } } else { return property->value; } } const TCHAR* getFileSafeStringProperty(Properties *properties, const TCHAR *propertyName, const TCHAR *defaultValue) { Property *property; TCHAR *buffer; int i; property = getInnerProperty(properties, propertyName, TRUE); if (property == NULL) { if (defaultValue != NULL) { addProperty(properties, NULL, 0, propertyName, defaultValue, FALSE, FALSE, FALSE, FALSE); } return defaultValue; } else { buffer = property->value; if (_tcschr(buffer, TEXT('%'))) { i = 0; while (buffer[i]) { if (buffer[i] == TEXT('%')) { buffer[i] = TEXT('_'); } i++; } } return buffer; } } /** * Does a quick sort of the property values, keeping the values together. */ void sortStringProperties(long unsigned int *propertyIndices, TCHAR **propertyNames, TCHAR **propertyValues, int low, int high) { int i = low; int j = high; long int tempIndex; TCHAR *tempName; TCHAR *tempValue; long unsigned int x = propertyIndices[(low + high) / 2]; do { while (propertyIndices[i] < x) { i++; } while (propertyIndices[j] > x) { j--; } if (i <= j) { /* Swap i and j values. */ tempIndex = propertyIndices[i]; tempName = propertyNames[i]; tempValue = propertyValues[i]; propertyIndices[i] = propertyIndices[j]; propertyNames[i] = propertyNames[j]; propertyValues[i] = propertyValues[j]; propertyIndices[j] = tempIndex; propertyNames[j] = tempName; propertyValues[j] = tempValue; i++; j--; } } while (i <= j); /* Recurse */ if (low < j) { sortStringProperties(propertyIndices, propertyNames, propertyValues, low, j); } if (i < high) { sortStringProperties(propertyIndices, propertyNames, propertyValues, i, high); } } /** * Returns a sorted array of all properties beginning with {propertyNameBase}. * Only numerical characters can be returned between the two. * * The calling code must always call freeStringProperties to make sure that the * malloced propertyNames, propertyValues, and propertyIndices arrays are freed * up correctly. This is only necessary if the function returns 0. * * @param properties The full properties structure. * @param propertyNameHead All matching properties must begin with this value. * @param propertyNameTail All matching properties must end with this value. * @param all If FALSE then the array will start with #1 and loop up until the * next property is not found, if TRUE then all properties will be * returned, even if there are gaps in the series. * @param matchAny If FALSE only numbers are allowed as placeholder * @param propertyNames Returns a pointer to a NULL terminated array of * property names. * @param propertyValues Returns a pointer to a NULL terminated array of * property values. * @param propertyIndices Returns a pointer to a 0 terminated array of * the index numbers used in each property name of * the propertyNames array. * * @return 0 if successful, -1 if there was an error. */ int getStringProperties(Properties *properties, const TCHAR *propertyNameHead, const TCHAR *propertyNameTail, int all, int matchAny, TCHAR ***propertyNames, TCHAR ***propertyValues, long unsigned int **propertyIndices) { int j; int k; size_t headLen; size_t tailLen; size_t thisLen; TCHAR *thisHead; TCHAR *thisTail; size_t i; Property *property; size_t indexLen; TCHAR indexS[11]; int ok; TCHAR c; int count; *propertyIndices = NULL; headLen = _tcslen(propertyNameHead); tailLen = _tcslen(propertyNameTail); for (j = 0; j < 2; j++) { count = 0; property = properties->first; while (property != NULL) { thisLen = _tcslen(property->name); if (matchAny && thisLen < headLen + tailLen - 1) { /* Too short, not what we are looking for. */ } else if (!matchAny && thisLen < headLen + tailLen + 1) { /* Too short, not what we are looking for. */ } else { thisHead = malloc(sizeof(TCHAR) * (headLen + 1)); if (!thisHead) { outOfMemory(TEXT("GSPS"), 1); } else { _tcsncpy(thisHead, property->name, headLen); thisHead[headLen] = 0; if (strcmpIgnoreCase(thisHead, propertyNameHead) == 0) { /* Head matches. */ thisTail = malloc(sizeof(TCHAR) * (tailLen + 1)); if (!thisTail) { outOfMemory(TEXT("GSPS"), 2); } else { _tcsncpy(thisTail, property->name + thisLen - tailLen, tailLen + 1); if (strcmpIgnoreCase(thisTail, propertyNameTail) == 0) { /* Tail matches. */ if (matchAny) { indexLen = thisLen - headLen - tailLen + 1; } else { indexLen = thisLen - headLen - tailLen; } if (indexLen <= 10) { _tcsncpy(indexS, property->name + headLen, indexLen); indexS[indexLen] = 0; ok = TRUE; for (i = 0; i < indexLen; i++) { c = indexS[i]; if (matchAny == FALSE && ((c < '0') || (c > '9'))) { ok = FALSE; break; } } if (ok) { if (*propertyIndices) { /* We found it. */ prepareProperty(properties, property, FALSE); (*propertyIndices)[count] = _tcstoul(indexS, NULL, 10); (*propertyNames)[count] = property->name; (*propertyValues)[count] = property->value; } count++; } } } free(thisTail); } } free(thisHead); } } /* Keep looking */ property = property->next; } if (*propertyIndices == NULL) { /* First pass */ *propertyNames = malloc(sizeof(TCHAR *) * (count + 1)); if (!(*propertyNames)) { outOfMemory(TEXT("GSPS"), 3); *propertyNames = NULL; *propertyValues = NULL; *propertyIndices = NULL; return -1; } *propertyValues = malloc(sizeof(TCHAR *) * (count + 1)); if (!(*propertyValues)) { outOfMemory(TEXT("GSPS"), 4); free(*propertyNames); *propertyNames = NULL; *propertyValues = NULL; *propertyIndices = NULL; return -1; } *propertyIndices = malloc(sizeof(long unsigned int) * (count + 1)); if (!(*propertyIndices)) { outOfMemory(TEXT("GSPS"), 5); free(*propertyNames); free(*propertyValues); *propertyNames = NULL; *propertyValues = NULL; *propertyIndices = NULL; return -1; } if (count == 0) { /* The count is 0 so no need to continue through the loop again. */ (*propertyNames)[0] = NULL; (*propertyValues)[0] = NULL; (*propertyIndices)[0] = 0; return 0; } } else { /* Second pass */ (*propertyNames)[count] = NULL; (*propertyValues)[count] = NULL; (*propertyIndices)[count] = 0; sortStringProperties(*propertyIndices, *propertyNames, *propertyValues, 0, count - 1); /* If we don't want all of the properties then we need to remove the extra ones. * Names and values are not allocated, so setting them to NULL is fine.*/ if (!all) { for (k = 0; k < count; k++) { if ((*propertyIndices)[k] != k + 1) { (*propertyNames)[k] = NULL; (*propertyValues)[k] = NULL; (*propertyIndices)[k] = 0; } } } /* for (k = 0; k < count; k++) { if ((*propertyNames)[k]) { _tprintf("[%d] #%lu: %s=%s\n", k, (*propertyIndices)[k], (*propertyNames)[k], (*propertyValues)[k]); } } */ return 0; } } /* For compiler */ return 0; } /** * Frees up an array of properties previously returned by getStringProperties(). */ void freeStringProperties(TCHAR **propertyNames, TCHAR **propertyValues, long unsigned int *propertyIndices) { /* The property names are not malloced. */ free(propertyNames); /* The property values are not malloced. */ free(propertyValues); free(propertyIndices); } int getIntProperty(Properties *properties, const TCHAR *propertyName, int defaultValue) { TCHAR buffer[16]; Property *property; int i; TCHAR c; int value; property = getInnerProperty(properties, propertyName, TRUE); if (property == NULL) { _sntprintf(buffer, 16, TEXT("%d"), defaultValue); addProperty(properties, NULL, 0, propertyName, buffer, FALSE, FALSE, FALSE, FALSE); return defaultValue; } else { value = (int)_tcstol(property->value, NULL, 0); /* Make sure that the property does not contain invalid characters. */ i = 0; do { c = property->value[i]; if ((i > 0) && (c == TEXT('\0'))) { /* Fall through */ } else if ((i == 0) && (c == TEXT('-'))) { /* Negative number. This is Ok. */ } else if ((c < TEXT('0')) || (c > TEXT('9'))) { if (i == 0) { /* If the bad character is the first character then use the default value. */ value = defaultValue; } if (properties->logWarnings) { log_printf(WRAPPER_SOURCE_WRAPPER, properties->logWarningLogLevel, TEXT("Encountered an invalid numerical value for configuration property %s=%s. Resolving to %d."), propertyName, property->value, value); } break; } i++; } while (c != TEXT('\0')); return value; } } int getBooleanProperty(Properties *properties, const TCHAR *propertyName, int defaultValue) { const TCHAR *defaultValueS; Property *property; const TCHAR *propertyValue; if (defaultValue) { defaultValueS = TEXT("true"); } else { defaultValueS = TEXT("false"); } property = getInnerProperty(properties, propertyName, TRUE); if (property == NULL) { propertyValue = defaultValueS; } else { propertyValue = property->value; } if (strcmpIgnoreCase(propertyValue, TEXT("true")) == 0) { return TRUE; } else if (strcmpIgnoreCase(propertyValue, TEXT("false")) == 0) { return FALSE; } else { if (properties->logWarnings) { log_printf(WRAPPER_SOURCE_WRAPPER, properties->logWarningLogLevel, TEXT("Encountered an invalid boolean value for configuration property %s=%s. Resolving to %s."), propertyName, propertyValue, TEXT("FALSE")); } return FALSE; } } int isQuotableProperty(Properties *properties, const TCHAR *propertyName) { Property *property; property = getInnerProperty(properties, propertyName, FALSE); if (property == NULL) { return FALSE; } else { return property->quotable; } } void dumpProperties(Properties *properties) { Property *property; property = properties->first; while (property != NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" name:%s value:%s"), property->name, property->value); property = property->next; } } /** * Set to TRUE if warnings about property values should be logged. */ void setLogPropertyWarnings(Properties *properties, int logWarnings) { properties->logWarnings = logWarnings; } /** * Level at which any property warnings are logged. */ void setLogPropertyWarningLogLevel(Properties *properties, int logLevel) { properties->logWarningLogLevel = logLevel; } /** * Returns the minimum value. This is used in place of the __min macro when the parameters should not be called more than once. */ int propIntMin(int value1, int value2) { if (value1 < value2) { return value1; } else { return value2; } } /** * Returns the maximum value. This is used in place of the __max macro when the parameters should not be called more than once. */ int propIntMax(int value1, int value2) { if (value1 > value2) { return value1; } else { return value2; } } /** Creates a linearized representation of all of the properties. * The returned buffer must be freed by the calling code. */ TCHAR *linearizeProperties(Properties *properties, TCHAR separator) { Property *property; size_t size; TCHAR *c; TCHAR *fullBuffer; TCHAR *work, *buffer; /* First we need to figure out how large a buffer will be needed to linearize the properties. */ size = 0; property = properties->first; while (property != NULL) { /* Add the length of the basic property. */ size += _tcslen(property->name); size++; /* '=' */ size += _tcslen(property->value); /* Handle any characters that will need to be escaped. */ c = property->name; while ((c = _tcschr(c, separator)) != NULL) { size++; c++; } c = property->value; while ((c = _tcschr(c, separator)) != NULL) { size++; c++; } size++; /* separator */ property = property->next; } size++; /* null terminated. */ /* Now that we know how much space this will all take up, allocate a buffer. */ fullBuffer = buffer = calloc(sizeof(TCHAR) , size); if (!fullBuffer) { outOfMemory(TEXT("LP"), 1); return NULL; } /* Now actually build up the output. Any separator characters need to be escaped with themselves. */ property = properties->first; while (property != NULL) { /* name */ work = property->name; while ((c = _tcschr(work, separator)) != NULL) { _tcsncpy(buffer, work, c - work + 1); buffer += c - work + 1; buffer[0] = separator; buffer++; work = c + 1; } _tcsncpy(buffer, work, size - _tcslen(fullBuffer)); buffer += _tcslen(work); /* equals */ buffer[0] = TEXT('='); buffer++; /* value */ work = property->value; while ((c = _tcschr(work, separator)) != NULL) { _tcsncpy(buffer, work, c - work + 1); buffer += c - work + 1; buffer[0] = separator; buffer++; work = c + 1; } _tcsncpy(buffer, work, size - _tcslen(fullBuffer)); buffer += _tcslen(work); /* separator */ buffer[0] = separator; buffer++; property = property->next; } /* null terminate. */ buffer[0] = 0; buffer++; return fullBuffer; } wrapper_3.5.26_src/src/c/property.h100644 0 0 30563 12440202301 14430 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ #ifndef _PROPERTY_H #define _PROPERTY_H #include "wrapper_hashmap.h" #ifndef TRUE #define TRUE -1 #endif #ifndef FALSE #define FALSE 0 #endif /* This defines the largest environment variable that we are able * to work with. It can be expanded if needed. */ #define MAX_PROPERTY_NAME_LENGTH 512 #define MAX_PROPERTY_VALUE_LENGTH 16384 #define MAX_PROPERTY_NAME_VALUE_LENGTH MAX_PROPERTY_NAME_LENGTH + 1 + MAX_PROPERTY_VALUE_LENGTH #define ENV_SOURCE_PARENT 1 #define ENV_SOURCE_APPLICATION 2 #define ENV_SOURCE_CONFIG 4 #ifdef WIN32 #define ENV_SOURCE_REG_SYSTEM 8 #define ENV_SOURCE_REG_ACCOUNT 16 #endif typedef struct EnvSrc EnvSrc; struct EnvSrc { int source; /* Source of the variable. */ TCHAR* name; /* Name of the environment variable. */ EnvSrc *next; /* Next variable in the chain. */ }; extern EnvSrc *baseEnvSrc; typedef struct Property Property; struct Property { TCHAR *name; /* The name of the property. */ TCHAR *value; /* The value of the property. */ int finalValue; /* TRUE if the Property can not be changed. */ int quotable; /* TRUE if quotes can be optionally added around the value. */ int internal; /* TRUE if the Property is internal. */ Property *next; /* Pointer to the next Property in a linked list */ Property *previous; /* Pointer to the next Property in a linked list */ }; typedef struct Properties Properties; struct Properties { int debugProperties; /* TRUE if debug information on Properties should be shown. */ int logWarnings; /* Flag that controls whether or not warnings will be logged. */ int logWarningLogLevel; /* Log level at which any log warnings will be logged. */ Property *first; /* Pointer to the first property. */ Property *last; /* Pointer to the last property. */ PHashMap warnedVarMap; /* Map of undefined environment variables for which the user was warned. */ }; /** * Sets an environment variable with the specified value. * The function will only set the variable if its value is changed, but if * it does, the call will result in a memory leak the size of the string: * "name=value". * * @param name Name of the variable being set. * @param value Value to be set, NULL to clear it. * @param source Where the variable came from. * Must be one of ENV_SOURCE_PARENT, ENV_SOURCE_APPLICATION, ENV_SOURCE_CONFIG, * or ENV_SOURCE_REG_SYSTEM or ENV_SOURCE_REG_ACCOUNT on Windows. * If value is ENV_SOURCE_PARENT then the value may be NULL and will never be * set to the environment. * * Return TRUE if there were any problems, FALSE otherwise. */ extern int setEnv(const TCHAR *name, const TCHAR *value, int source); /** * Parses a property value and populates any environment variables. If the expanded * environment variable would result in a string that is longer than bufferLength * the value is truncated. * * @param warnUndefinedVars Log warnings about missing environment variables. * @param warnedUndefVarMap Map of variables which have previously been logged, may be NULL if warnUndefinedVars false. * @param warnLogLevel Log level at which any warnings will be logged. */ extern void evaluateEnvironmentVariables(const TCHAR *propertyValue, TCHAR *buffer, int bufferLength, int warnUndefinedVars, PHashMap warnedUndefVarMap, int warnLogLevel); /** * This function returns a reference to a static buffer and is NOT thread safe. * Check implementation notes before using. */ extern TCHAR* generateTimeValue(const TCHAR* format, struct tm *timeTM); /** * This function returns a reference to a static buffer and is NOT thread safe. * Check implementation notes before using. */ extern TCHAR* generateRandValue(const TCHAR* format); /** * Create a Properties structure loaded in from the specified file. * Must call disposeProperties to free up allocated memory. * * @param properties Properties structure to load into. * @param filename File to load the properties from. * @param preload TRUE if this is a preload call that should have supressed error output. * @param argCommand Argument passed to the binary. * @param originalWorkingDir Working directory of the binary at the moment it was launched. * @param isDebugging Flag that controls whether or not debug output will be logged. * * @return TRUE if there were any problems, FALSE if successful. */ extern int loadProperties(Properties *properties, const TCHAR* filename, int preload, const TCHAR *argCommand, const TCHAR *originalWorkingDir, int isDebugging); /** * Create a Properties structure. Must call disposeProperties to free up * allocated memory. */ extern Properties* createProperties(); /** * Free all memory allocated by a Properties structure. The properties * pointer will no longer be valid. */ extern void disposeProperties(Properties *properties); /** * Free all memory allocated by a Properties structure. The properties * pointer will no longer be valid. */ extern void disposeEnvironment(); /** * Remove a single Property from a Properties. All associated memory is * freed up. */ extern void removeProperty(Properties *properties, const TCHAR *propertyName); /** * Used to set a NULL terminated list of property names whose values should be * escaped when read in from a file. '\\' will become '\' and '\n' will * become '^J', all other characters following '\' will be left as is. * * @param propertyNames NULL terminated list of property names. Property names * can contain a single '*' wildcard which will match 0 or * more characters. */ extern void setEscapedProperties(const TCHAR **propertyNames); /** * Returns true if the specified property matches one of the property names * previosly set in a call to setEscapableProperties() * * @param propertyName Property name to test. * * @return TRUE if the property should be escaped. FALSE otherwise. */ extern int isEscapedProperty(const TCHAR *propertyName); /** * Adds a single property to the properties structure. * * @param properties Properties structure to add to. * @param filename Name of the file from which the property was loaded. NULL, if not from a file. * @param lineNum Line number of the property declaration in the file. Ignored if filename is NULL. * @param propertyName Name of the new Property. * @param propertyValue Initial property value. * @param finalValue TRUE if the property should be set as static. * @param quotable TRUE if the property could contain quotes. * @param escapable TRUE if the propertyValue can be escaped if its propertyName * is in the list set with setEscapableProperties(). * @param internal TRUE if the property is a Wrapper internal property. * * @return The newly created Property, or NULL if there was a reported error. */ extern Property* addProperty(Properties *properties, const TCHAR* filename, int lineNum, const TCHAR *propertyName, const TCHAR *propertyValue, int finalValue, int quotable, int escapable, int internal); /** * Takes a name/value pair in the form = and attempts to add * it to the specified properties table. * * @param properties Properties structure to add to. * @param filename Name of the file from which the property was loaded. NULL, if not from a file. * @param lineNum Line number of the property declaration in the file. Ignored if filename is NULL. * @param propertyNameValue The "name=value" pair to create the property from. * @param finalValue TRUE if the property should be set as static. * @param quotable TRUE if the property could contain quotes. * @param internal TRUE if the property is a Wrapper internal property. * * Returns 0 if successful, otherwise 1 */ extern int addPropertyPair(Properties *properties, const TCHAR* filename, int lineNum, const TCHAR *propertyNameValue, int finalValue, int quotable, int internal); extern const TCHAR* getStringProperty(Properties *properties, const TCHAR *propertyName, const TCHAR *defaultValue); extern const TCHAR* getFileSafeStringProperty(Properties *properties, const TCHAR *propertyName, const TCHAR *defaultValue); /** * Returns a sorted array of all properties beginning with {propertyNameBase}. * Only numerical characters can be returned between the two. * * The calling code must always call freeStringProperties to make sure that the * malloced propertyNames, propertyValues, and propertyIndices arrays are freed * up correctly. This is only necessary if the function returns 0. * * @param properties The full properties structure. * @param propertyNameHead All matching properties must begin with this value. * @param propertyNameTail All matching properties must end with this value. * @param all If FALSE then the array will start with #1 and loop up until the * next property is not found, if TRUE then all properties will be * returned, even if there are gaps in the series. * @param matchAny If FALSE only numbers are allowed as placeholder * @param propertyNames Returns a pointer to a NULL terminated array of * property names. * @param propertyValues Returns a pointer to a NULL terminated array of * property values. * @param propertyIndices Returns a pointer to a 0 terminated array of * the index numbers used in each property name of * the propertyNames array. * * @return 0 if successful, -1 if there was an error. */ extern int getStringProperties(Properties *properties, const TCHAR *propertyNameHead, const TCHAR *propertyNameTail, int all, int matchAny, TCHAR ***propertyNames, TCHAR ***propertyValues, long unsigned int **propertyIndices); /** * Frees up an array of properties previously returned by getStringProperties(). */ extern void freeStringProperties(TCHAR **propertyNames, TCHAR **propertyValues, long unsigned int *propertyIndices); extern int getIntProperty(Properties *properties, const TCHAR *propertyName, int defaultValue); extern int getBooleanProperty(Properties *properties, const TCHAR *propertyName, int defaultValue); extern int isQuotableProperty(Properties *properties, const TCHAR *propertyName); extern void dumpProperties(Properties *properties); /** * Set to TRUE if warnings about property values should be logged. */ extern void setLogPropertyWarnings(Properties *properties, int logWarnings); /** * Level at which any property warnings are logged. */ extern void setLogPropertyWarningLogLevel(Properties *properties, int logLevel); /** * Returns the minimum value. This is used in place of the __min macro when the parameters should not be called more than once. */ extern int propIntMin(int value1, int value2); /** * Returns the maximum value. This is used in place of the __max macro when the parameters should not be called more than once. */ extern int propIntMax(int value1, int value2); /** Creates a linearized representation of all of the properties. * The returned buffer must be freed by the calling code. */ extern TCHAR *linearizeProperties(Properties *properties, TCHAR separator); #endif wrapper_3.5.26_src/src/c/psapi.h100644 0 0 7517 12440202301 13643 0ustar 0 0 /*++ BUILD Version: 0001 // Increment this if a change has global effects Copyright (c) 1994 Microsoft Corporation Module Name: psapi.h Abstract: Include file for APIs provided by PSAPI.DLL Author: Richard Shupak [richards] 06-Jan-1994 Revision History: --*/ #ifndef _PSAPI_H_ #define _PSAPI_H_ #ifdef __cplusplus extern "C" { #endif BOOL WINAPI EnumProcesses( DWORD * lpidProcess, DWORD cb, DWORD * cbNeeded ); BOOL WINAPI EnumProcessModules( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ); DWORD WINAPI GetModuleBaseNameA( HANDLE hProcess, HMODULE hModule, LPSTR lpBaseName, DWORD nSize ); DWORD WINAPI GetModuleBaseNameW( HANDLE hProcess, HMODULE hModule, LPWSTR lpBaseName, DWORD nSize ); #ifdef UNICODE #define GetModuleBaseName GetModuleBaseNameW #else #define GetModuleBaseName GetModuleBaseNameA #endif // !UNICODE DWORD WINAPI GetModuleFileNameExA( HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); DWORD WINAPI GetModuleFileNameExW( HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize ); #ifdef UNICODE #define GetModuleFileNameEx GetModuleFileNameExW #else #define GetModuleFileNameEx GetModuleFileNameExA #endif // !UNICODE typedef struct _MODULEINFO { LPVOID lpBaseOfDll; DWORD SizeOfImage; LPVOID EntryPoint; } MODULEINFO, *LPMODULEINFO; BOOL WINAPI GetModuleInformation( HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb ); BOOL WINAPI EmptyWorkingSet( HANDLE hProcess ); BOOL WINAPI QueryWorkingSet( HANDLE hProcess, PVOID pv, DWORD cb ); BOOL WINAPI InitializeProcessForWsWatch( HANDLE hProcess ); typedef struct _PSAPI_WS_WATCH_INFORMATION { LPVOID FaultingPc; LPVOID FaultingVa; } PSAPI_WS_WATCH_INFORMATION, *PPSAPI_WS_WATCH_INFORMATION; BOOL WINAPI GetWsChanges( HANDLE hProcess, PPSAPI_WS_WATCH_INFORMATION lpWatchInfo, DWORD cb ); DWORD WINAPI GetMappedFileNameW( HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, DWORD nSize ); DWORD WINAPI GetMappedFileNameA( HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, DWORD nSize ); #ifdef UNICODE #define GetMappedFilenameEx GetMappedFilenameExW #else #define GetMappedFilenameEx GetMappedFilenameExA #endif // !UNICODE BOOL WINAPI EnumDeviceDrivers( LPVOID *lpImageBase, DWORD cb, LPDWORD lpcbNeeded ); DWORD WINAPI GetDeviceDriverBaseNameA( LPVOID ImageBase, LPSTR lpBaseName, DWORD nSize ); DWORD WINAPI GetDeviceDriverBaseNameW( LPVOID ImageBase, LPWSTR lpBaseName, DWORD nSize ); #ifdef UNICODE #define GetDeviceDriverBaseName GetDeviceDriverBaseNameW #else #define GetDeviceDriverBaseName GetDeviceDriverBaseNameA #endif // !UNICODE DWORD WINAPI GetDeviceDriverFileNameA( LPVOID ImageBase, LPSTR lpFilename, DWORD nSize ); DWORD WINAPI GetDeviceDriverFileNameW( LPVOID ImageBase, LPWSTR lpFilename, DWORD nSize ); #ifdef UNICODE #define GetDeviceDriverFileName GetDeviceDriverFileNameW #else #define GetDeviceDriverFileName GetDeviceDriverFileNameA #endif // !UNICODE // Structure for GetProcessMemoryInfo() typedef struct _PROCESS_MEMORY_COUNTERS { DWORD cb; DWORD PageFaultCount; DWORD PeakWorkingSetSize; DWORD WorkingSetSize; DWORD QuotaPeakPagedPoolUsage; DWORD QuotaPagedPoolUsage; DWORD QuotaPeakNonPagedPoolUsage; DWORD QuotaNonPagedPoolUsage; DWORD PagefileUsage; DWORD PeakPagefileUsage; } PROCESS_MEMORY_COUNTERS; typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS; BOOL WINAPI GetProcessMemoryInfo( HANDLE Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb ); #ifdef __cplusplus } #endif #endif wrapper_3.5.26_src/src/c/resource.h100644 0 0 667 12440202301 14335 0ustar 0 0 //{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by Wrapper.rc // #define IDI_WRAPPER 102 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 106 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1002 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif wrapper_3.5.26_src/src/c/runnmake.bat100644 0 0 774 12440202300 14643 0ustar 0 0 @echo off setlocal rem Copyright (c) 1999, 2014 Tanuki Software Inc. rem rem Java Service Wrapper windows build script. This script is designed to be rem called by the ant build.xml file. rem rem %1 Makefile name rem %2 Visual Studio environment script rem %3 script argument rem %4 script argument rem %5 script argument echo Configuring the Visual Studio environment... echo call %2 %3 %4 %5 call %2 %3 %4 %5 echo Run the make file... echo nmake /f %1 /c all nmake /f %1 /c all wrapper_3.5.26_src/src/c/test_example.c100644 0 0 3007 12440202301 15202 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #include #include #include #include "CUnit/Basic.h" #include "property.h" /******************************************************************** * Example Tests *******************************************************************/ /** * The suite initialization function. * Opens the temporary file used by the tests. * Returns zero on success, non-zero otherwise. */ int tsEX_init_suite1(void) { return 0; } /** * The suite cleanup function. * Closes the temporary file used by the tests. * Returns zero on success, non-zero otherwise. */ int tsEX_clean_suite1(void) { return 0; } /** * Simple test that passes. */ void tsEX_testPass(void) { CU_ASSERT_EQUAL(0, 0); } /** * Simple test that passes. */ void tsEX_testFail(void) { CU_ASSERT_NOT_EQUAL(0, 1); } int tsEX_suiteExample() { CU_pSuite exampleSuite; exampleSuite = CU_add_suite("Example Suite", tsEX_init_suite1, tsEX_clean_suite1); if (NULL == exampleSuite) { return CU_get_error(); } CU_add_test(exampleSuite, "Pass", tsEX_testPass); CU_add_test(exampleSuite, "Fail", tsEX_testFail); return FALSE; } wrapper_3.5.26_src/src/c/test_filter.c100644 0 0 13063 12440202301 15057 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #include #include #include #include "CUnit/Basic.h" #include "logger.h" #include "property.h" #include "wrapper.h" /******************************************************************** * Filter Tests *******************************************************************/ #define TSFLTR_WORK_BUFFER_LEN 4096 TCHAR tsFLTR_workBuffer[TSFLTR_WORK_BUFFER_LEN]; void tsFLTR_dummyLogFileChanged(const TCHAR *logFile) { } int tsFLTR_init_wrapper(void) { initLogging(tsFLTR_dummyLogFileChanged); logRegisterThread(WRAPPER_THREAD_MAIN); setLogfileLevelInt(LEVEL_NONE); setConsoleLogFormat(TEXT("LPM")); setConsoleLogLevelInt(LEVEL_DEBUG); setConsoleFlush(TRUE); setSyslogLevelInt(LEVEL_NONE); return 0; } int tsFLTR_clean_wrapper(void) { disposeLogging(); return 0; } void tsFLTR_subTestWrapperWildcardMatch(const TCHAR *pattern, const TCHAR *text, size_t expectedMinLen, int expectedMatch) { size_t minLen; int matched; minLen = wrapperGetMinimumTextLengthForPattern(pattern); if (minLen != expectedMinLen) { _sntprintf(tsFLTR_workBuffer, TSFLTR_WORK_BUFFER_LEN, TEXT("wrapperGetMinimumTextLengthForPattern(\"%s\") returned %d rather than expected %d."), pattern, minLen, expectedMinLen); _tprintf(TEXT("%s\n"), tsFLTR_workBuffer); CU_FAIL(tsFLTR_workBuffer); } else { _sntprintf(tsFLTR_workBuffer, TSFLTR_WORK_BUFFER_LEN, TEXT("wrapperGetMinimumTextLengthForPattern(\"%s\") returned %d."), pattern, minLen); CU_PASS(tsFLTR_workBuffer); } matched = wrapperWildcardMatch(text, pattern, expectedMinLen); if (matched != expectedMatch) { _sntprintf(tsFLTR_workBuffer, TSFLTR_WORK_BUFFER_LEN, TEXT("wrapperWildcardMatch(\"%s\", \"%s\", %d) returned %s rather than expected %s."), text, pattern, expectedMinLen, (matched ? TEXT("TRUE") : TEXT("FALSE")), (expectedMatch ? TEXT("TRUE") : TEXT("FALSE"))); _tprintf(TEXT("%s\n"), tsFLTR_workBuffer); CU_FAIL(tsFLTR_workBuffer); } else { _sntprintf(tsFLTR_workBuffer, TSFLTR_WORK_BUFFER_LEN, TEXT("wrapperWildcardMatch(\"%s\", \"%s\", %d) returned %s."), text, pattern, expectedMinLen, (matched ? TEXT("TRUE") : TEXT("FALSE"))); CU_PASS(tsFLTR_workBuffer); } } void tsFLTR_testWrapperWildcardMatch() { tsFLTR_subTestWrapperWildcardMatch(TEXT("a"), TEXT("a"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("a"), TEXT("b"), 1, FALSE); tsFLTR_subTestWrapperWildcardMatch(TEXT("a"), TEXT(""), 1, FALSE); tsFLTR_subTestWrapperWildcardMatch(TEXT("a"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("b"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("c"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("d"), TEXT("abc"), 1, FALSE); tsFLTR_subTestWrapperWildcardMatch(TEXT("?"), TEXT("a"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("?"), TEXT(""), 1, FALSE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*"), TEXT(""), 0, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*"), TEXT("a"), 0, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*"), TEXT("abc"), 0, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*a"), TEXT("a"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*a"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*b"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("a*"), TEXT("a"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("a*"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("b*"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*a*"), TEXT("a"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*a*"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*b*"), TEXT("abc"), 1, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("HEAD*TAIL"), TEXT("This is the HEAD and this is the TAIL....."), 8, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("HEAD**TAIL"), TEXT("This is the HEAD and this is the TAIL....."), 8, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*HEAD*TAIL*"), TEXT("This is the HEAD and this is the TAIL....."), 8, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("HEAD*TAIL"), TEXT("This is the HEAD and this is the TaIL....."), 8, FALSE); tsFLTR_subTestWrapperWildcardMatch(TEXT("HEAD**TAIL"), TEXT("This is the HEAD and this is the TaIL....."), 8, FALSE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*HEAD*TAIL*"), TEXT("This is the HEAD and this is the TaIL....."), 8, FALSE); tsFLTR_subTestWrapperWildcardMatch(TEXT("HEAD*TA?L"), TEXT("This is the HEAD and this is the TAIL....."), 8, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("HEAD**TA?L"), TEXT("This is the HEAD and this is the TAIL....."), 8, TRUE); tsFLTR_subTestWrapperWildcardMatch(TEXT("*HEAD*TA?L*"), TEXT("This is the HEAD and this is the TAIL....."), 8, TRUE); } int tsFLTR_suiteFilter() { CU_pSuite filterSuite; filterSuite = CU_add_suite("Filter Suite", tsFLTR_init_wrapper, tsFLTR_clean_wrapper); if (NULL == filterSuite) { return CU_get_error(); } CU_add_test(filterSuite, "wrapperWildcardMatch", tsFLTR_testWrapperWildcardMatch); return FALSE; } wrapper_3.5.26_src/src/c/test_hashmap.c100644 0 0 17174 12440202301 15222 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #include #include #include #include "CUnit/Basic.h" #include "logger.h" #include "property.h" #include "wrapper_hashmap.h" /******************************************************************** * Hash Map Tests *******************************************************************/ TCHAR *tsHASH_randomChars = TEXT("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"); #define TSHASH_WORK_BUFFER_LEN 4096 TCHAR tsHASH_workBuffer[TSHASH_WORK_BUFFER_LEN]; int tsHASH_getRandom(int min, int max) { int num; int rNum; num = max + 1 - min; if (num <= 0) { return min; } /* Some platforms use very large RAND_MAX values that cause overflow problems in our math */ if (RAND_MAX > 0x10000) { rNum = (int)((rand() >> 8) * num / (RAND_MAX >> 8)); } else { rNum = (int)(rand() * num / RAND_MAX); } return min + rNum; } /** * Creates a string of random characters that is within the specified range of lengths. * It is the responsibility of the caller to free up the string. * * @param minLen Minimum Length of the string. * @param maxLen Maximum Length of the string. * * @return the requested string, or NULL if out of memory. */ TCHAR *tsHASH_buildRandomString(int minLen, int maxLen) { int num; int len; TCHAR *str; int i; num = _tcslen(tsHASH_randomChars); len = tsHASH_getRandom(minLen, maxLen); str = malloc(sizeof(TCHAR) * (len + 1)); if (!str) { return NULL; } for (i = 0; i < len; i++) { str[i] = tsHASH_randomChars[tsHASH_getRandom(0, num - 1)]; } str[len] = TEXT('\0'); return str; } /** * Creates a string of random characters that is within the specified range of lengths. * It is the responsibility of the caller to free up the string. * * @param minLen Minimum Length of the string. * @param maxLen Maximum Length of the string. * * @return the requested string, or NULL if out of memory. */ TCHAR *tsHASH_buildRandomStringWithTail(int minLen, int maxLen, int tail) { int num; size_t len; size_t strLen; TCHAR *str; size_t i; TCHAR tailStr[32]; _sntprintf(tailStr, 32, TEXT("-%d"), tail); num = _tcslen(tsHASH_randomChars); len = tsHASH_getRandom(minLen, maxLen); strLen = len + _tcslen(tailStr) + 1; str = malloc(sizeof(TCHAR) * strLen); if (!str) { return NULL; } for (i = 0; i < len; i++) { str[i] = tsHASH_randomChars[tsHASH_getRandom(0, num - 1)]; } str[len] = TEXT('\0'); _tcsncat(str, tailStr, strLen); return str; } /** * Frees up an array and its contents. Depends on the values being NULL if they are not allocated. * * @param array Array to be freed. */ void tsHASH_freeTCHARArray(TCHAR **array, int len) { int i; if (array) { for (i = 0; i < len; i++) { if (array[i]) { free(array[i]); } } free(array); } } void tsHASH_hashMapCommon(int buckets, int valueCount) { PHashMap hashMap; int i; TCHAR **keys = NULL; TCHAR **values = NULL; const TCHAR *value; hashMap = newHashMap(buckets); if (valueCount > 0) { keys = malloc(sizeof(TCHAR*) * valueCount); if (!keys) { CU_FAIL(TEXT("Out of memory HMC1")); freeHashMap(hashMap); return; } memset(keys, 0, sizeof(TCHAR*) * valueCount); values = malloc(sizeof(TCHAR*) * valueCount); if (!values) { CU_FAIL(TEXT("Out of memory HMC2")); tsHASH_freeTCHARArray(keys, valueCount); freeHashMap(hashMap); return; } memset(values, 0, sizeof(TCHAR*) * valueCount); /* Generate and add key-value pairs. */ for (i = 0; i < valueCount; i++) { keys[i] = tsHASH_buildRandomStringWithTail(1, 20, i); if (!keys[i]) { CU_FAIL(TEXT("Out of memory HMC3")); tsHASH_freeTCHARArray(keys, valueCount); tsHASH_freeTCHARArray(values, valueCount); freeHashMap(hashMap); return; } values[i] = tsHASH_buildRandomString(1, 255); if (!values[i]) { CU_FAIL(TEXT("Out of memory HMC3")); tsHASH_freeTCHARArray(keys, valueCount); tsHASH_freeTCHARArray(values, valueCount); freeHashMap(hashMap); return; } hashMapPutKWVW(hashMap, keys[i], values[i]); } #ifdef _DEBUG_HASHMAP dumpHashMapStats(hashMap); #endif /* Now check to make sure all of the values were set correctly. */ for (i = 0; i < valueCount; i++) { value = hashMapGetKWVW(hashMap, keys[i]); if (value) { if (_tcscmp(values[i], value) != 0) { _sntprintf(tsHASH_workBuffer, TSHASH_WORK_BUFFER_LEN, TEXT("hashMapGetKWVW(map, \"%s\") returned \"%s\" rather than expected \"%s\"."), keys[i], value, values[i]); _tprintf(TEXT("%s\n"), tsHASH_workBuffer); CU_FAIL(tsHASH_workBuffer); } else { _sntprintf(tsHASH_workBuffer, TSHASH_WORK_BUFFER_LEN, TEXT("hashMapGetKWVW(map, \"%s\") returned \"%s\" as expected."), keys[i], value); CU_PASS(tsHASH_workBuffer); } } else { _sntprintf(tsHASH_workBuffer, TSHASH_WORK_BUFFER_LEN, TEXT("hashMapGetKWVW(map, \"%s\") returned NULL rather than expected \"%s\"."), keys[i], values[i]); _tprintf(TEXT("%s\n"), tsHASH_workBuffer); CU_FAIL(tsHASH_workBuffer); } } /* Check for a value that will not be in the map. */ value = hashMapGetKWVW(hashMap, TEXT("$")); if (value) { _sntprintf(tsHASH_workBuffer, TSHASH_WORK_BUFFER_LEN, TEXT("hashMapGetKWVW(map, \"$\") returned \"%s\" rather than expected NULL."), value); _tprintf(TEXT("%s\n"), tsHASH_workBuffer); CU_FAIL(tsHASH_workBuffer); } else { _sntprintf(tsHASH_workBuffer, TSHASH_WORK_BUFFER_LEN, TEXT("hashMapGetKWVW(map, \"$\") returned NULL as expected.")); CU_PASS(tsHASH_workBuffer); } tsHASH_freeTCHARArray(keys, valueCount); tsHASH_freeTCHARArray(values, valueCount); } freeHashMap(hashMap); } /** * Make sure we can create and destroy an empty hash map. */ void tsHASH_testHashMapEmpty() { tsHASH_hashMapCommon(100, 0); } /** * Make sure we can create and destroy an sparsely filled hash map that has many empty buckets. */ void tsHASH_testHashMapSparse() { tsHASH_hashMapCommon(100, 10); } /** * Make sure we can create and destroy an sparsely filled hash map that has many empty buckets. */ void tsHASH_testHashMapLarge() { tsHASH_hashMapCommon(100, 10000); } int tsHASH_suiteHashMap() { CU_pSuite hashMapSuite; hashMapSuite = CU_add_suite("HashMap Suite", NULL, NULL); if (NULL == hashMapSuite) { return CU_get_error(); } CU_add_test(hashMapSuite, "empty HashMap", tsHASH_testHashMapEmpty); CU_add_test(hashMapSuite, "sparce HashMap", tsHASH_testHashMapSparse); CU_add_test(hashMapSuite, "large HashMap", tsHASH_testHashMapLarge); return FALSE; } wrapper_3.5.26_src/src/c/test_javaadditionalparam.c100644 0 0 3357 12440202301 17552 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #include #include #include #include "CUnit/Basic.h" #include "logger.h" #include "property.h" #include "wrapper.h" /******************************************************************** * JavaAdditionalParam Utilities *******************************************************************/ /* TODO: Currently the source of tsJAP_testJavaAdditionalParamSuite is in wrapper.c Should we move it in here? */ void tsJAP_dummyLogFileChanged(const TCHAR *logFile) { } int tsJAP_init_properties(void) { initLogging(tsJAP_dummyLogFileChanged); logRegisterThread(WRAPPER_THREAD_MAIN); setLogfileLevelInt(LEVEL_NONE); setConsoleLogFormat(TEXT("LPM")); setConsoleLogLevelInt(LEVEL_DEBUG); setConsoleFlush(TRUE); setSyslogLevelInt(LEVEL_NONE); properties = createProperties(); return properties ? 0 : 1; } int tsJAP_clean_properties(void) { disposeLogging(); disposeProperties(properties); return 0; } int tsJAP_suiteJavaAdditionalParam() { CU_pSuite javaAdditionalParamSuite; javaAdditionalParamSuite = CU_add_suite("Java Additional Parameter Suite", tsJAP_init_properties, tsJAP_clean_properties); if (NULL == javaAdditionalParamSuite) { return CU_get_error(); } CU_add_test(javaAdditionalParamSuite, "loadJavaAdditionalCallback()", tsJAP_testJavaAdditionalParamSuite); return FALSE; } wrapper_3.5.26_src/src/c/testsuite.c100644 0 0 10460 12440202301 14562 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /* NOTES: * * See for ASSERTS: * http://cunit.sourceforge.net/doc/writing_tests.html#tests */ #include #include #include #include "CUnit/Automated.h" #include "CUnit/Basic.h" #include #include "testsuite.h" #include "logger.h" /******************************************************************** * Main *******************************************************************/ static void showHelp(TCHAR *app) { _tprintf(TEXT("Wrapper testsuite help.\n")); _tprintf(TEXT("%s \n"), app); _tprintf(TEXT("\n")); _tprintf(TEXT("Commands:\n")); _tprintf(TEXT(" --basic : Runs all tests in basic mode. Only summaries visible.\n")); _tprintf(TEXT(" --auto : Runs all tests in automatic mode. Output visible but results output to file.\n")); _tprintf(TEXT(" See CUnitAutomated-Results.xml for results.\n")); _tprintf(TEXT(" --console : Interactive mode.\n")); _tprintf(TEXT(" --help : This help.\n")); _tprintf(TEXT("\n")); } /* The main() function for setting up and running the tests. * Returns a CUE_SUCCESS on successful running, another * CUnit error code on failure. */ int main(int argc, char **cargv) { TCHAR **argv; int i; size_t req; int errorCode; argv = malloc(argc * sizeof * argv); if (!argv) { _tprintf(TEXT("Out of Memory in Main\n")); return 1; } for (i = 0; i < argc; i++) { req = mbstowcs(NULL, cargv[i], MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { _tprintf(TEXT("Encoding problem with arguments in Main\n")); while (--i > 0) { free(argv[i]); } free(argv); return 1; } argv[i] = malloc(sizeof(TCHAR) * (req + 1)); if (!argv[i]) { _tprintf(TEXT("Out of Memory in Main\n")); while (--i > 0) { free(argv[i]); } free(argv); return 1; } mbstowcs(argv[i], cargv[i], req + 1); argv[i][req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ } /* Initialize the random seed. */ srand((unsigned)time(NULL)); /* initialize the CUnit test registry */ if (CUE_SUCCESS != CU_initialize_registry()) { errorCode = CU_get_error(); goto error; } /* add a suite to the registry */ if (tsEX_suiteExample()) { CU_cleanup_registry(); errorCode = CU_get_error(); goto error; } if (tsFLTR_suiteFilter()) { CU_cleanup_registry(); errorCode = CU_get_error(); goto error; } if (tsJAP_suiteJavaAdditionalParam()) { CU_cleanup_registry(); errorCode = CU_get_error(); goto error; } if (tsHASH_suiteHashMap()) { CU_cleanup_registry(); errorCode = CU_get_error(); goto error; } if (argc < 2) { showHelp(argv[0]); errorCode = 1; } else if (strcmpIgnoreCase(argv[1], TEXT("--basic")) == 0) { /* Run all tests using the CUnit Basic interface */ CU_set_output_filename("testsuite"); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); CU_cleanup_registry(); errorCode = CU_get_error(); } else if (strcmpIgnoreCase(argv[1], TEXT("--auto")) == 0) { /* Run all tests using the CUnit Automated interface */ CU_list_tests_to_file(); CU_automated_run_tests(); CU_cleanup_registry(); errorCode = CU_get_error(); } else if (strcmpIgnoreCase(argv[1], TEXT("--console")) == 0) { /* Run all tests using the CUnit Console interface */ CU_console_run_tests(); CU_cleanup_registry(); errorCode = CU_get_error(); } else { showHelp(argv[0]); errorCode = 1; } error: for (i = 0; i < argc; i++) { free(argv[i]); } free(argv); return errorCode; } wrapper_3.5.26_src/src/c/testsuite.h100644 0 0 1160 12440202301 14544 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #ifndef _TESTSUITE_H #define _TESTSUITE_H #include "CUnit/Basic.h" #include "wrapper_i18n.h" extern int tsEX_suiteExample(); extern int tsFLTR_suiteFilter(); extern int tsJAP_suiteJavaAdditionalParam(); extern int tsHASH_suiteHashMap(); #endif wrapper_3.5.26_src/src/c/wrapper.c100644 0 0 1311754 12440202301 14264 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * Author: * Leif Mortenson * Ryan Shaw */ #ifdef WIN32 /* need the 2 following includes to use IPv6 and need wsock32.lib in the makefile */ #include #include #endif #include #include #include #include #include #include #include #ifdef CUNIT #include "CUnit/Basic.h" #endif #include "wrapper_i18n.h" #include "wrapperinfo.h" #include "wrapper.h" #include "logger.h" #include "logger_file.h" #include "wrapper_file.h" #ifdef WIN32 #include #include #include #include #include /* MS Visual Studio 8 went and deprecated the POXIX names for functions. * Fixing them all would be a big headache for UNIX versions. */ #pragma warning(disable : 4996) /* Defines for MS Visual Studio 6 */ #ifndef _INTPTR_T_DEFINED typedef long intptr_t; #define _INTPTR_T_DEFINED #endif #else /* UNIX */ #include #include #include #include #include #include #include #include #include #include #include #include #define SOCKET int #define HANDLE int #define INVALID_HANDLE_VALUE -1 #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #if defined(SOLARIS) #include #include #elif defined(AIX) || defined(HPUX) || defined(MACOSX) || defined(OSF1) #elif defined(IRIX) #define PATH_MAX FILENAME_MAX #elif defined(FREEBSD) #include #include #else /* LINUX */ #include #endif #endif /* WIN32 */ /* Define some common defines to make cross platform code a bit cleaner. */ #ifdef WIN32 #define WRAPPER_EADDRINUSE WSAEADDRINUSE #define WRAPPER_EWOULDBLOCK WSAEWOULDBLOCK #define WRAPPER_EACCES WSAEACCES #else #define WRAPPER_EADDRINUSE EADDRINUSE #define WRAPPER_EWOULDBLOCK EWOULDBLOCK #define WRAPPER_EACCES EACCES #endif WrapperConfig *wrapperData; char packetBufferMB[MAX_LOG_SIZE + 1]; TCHAR packetBufferW[MAX_LOG_SIZE + 1]; TCHAR *keyChars = TEXT("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"); /* Properties structure loaded in from the configuration file. */ Properties *properties; /* Mutex for syncronization of the tick timer. */ #ifdef WIN32 HANDLE tickMutexHandle = NULL; #else pthread_mutex_t tickMutex = PTHREAD_MUTEX_INITIALIZER; #endif /* Server Pipe Handles. */ HANDLE protocolActiveServerPipeIn = INVALID_HANDLE_VALUE; HANDLE protocolActiveServerPipeOut = INVALID_HANDLE_VALUE; /* Flag for indicating the connected pipes */ int protocolActiveServerPipeConnected = FALSE; /* Server Socket. */ SOCKET protocolActiveServerSD = INVALID_SOCKET; /* Client Socket. */ SOCKET protocolActiveBackendSD = INVALID_SOCKET; #ifndef IN6ADDR_LOOPBACK_INIT /* even if I include ws2ipdef.h, it doesn't define IN6ADDR_LOOPBACK_INIT, so that's why I define it here */ #define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } #endif #define LOOPBACK_IPv4 "127.0.0.1" struct in6_addr LOOPBACK_IPv6 = IN6ADDR_LOOPBACK_INIT; int disposed = FALSE; int loadConfiguration(); #define READ_BUFFER_BLOCK_SIZE 1024 char *wrapperChildWorkBuffer = NULL; size_t wrapperChildWorkBufferSize = 0; size_t wrapperChildWorkBufferLen = 0; time_t wrapperChildWorkLastDataTime = 0; int wrapperChildWorkLastDataTimeMillis = 0; /** * Constructs a tm structure from a pair of Strings like "20091116" and "1514". * The time returned will be in the local time zone. This is not 100% accurate * as it doesn't take into account the time zone in which the dates were * originally set. */ struct tm getInfoTime(const TCHAR *date, const TCHAR *time) { struct tm buildTM; TCHAR temp[5]; memset(&buildTM, 0, sizeof(struct tm)); /* Year */ _tcsncpy( temp, date, 4 ); temp[4] = 0; buildTM.tm_year = _ttoi( temp ) - 1900; /* Month */ _tcsncpy( temp, date + 4, 2 ); temp[2] = 0; buildTM.tm_mon = _ttoi( temp ) - 1; /* Day */ _tcsncpy( temp, date + 6, 2 ); temp[2] = 0; buildTM.tm_mday = _ttoi( temp ); /* Hour */ _tcsncpy( temp, time, 2 ); temp[2] = 0; buildTM.tm_hour = _ttoi( temp ); /* Minute */ _tcsncpy( temp, time + 2, 2 ); temp[2] = 0; buildTM.tm_min = _ttoi( temp ); return buildTM; } struct tm wrapperGetReleaseTime() { return getInfoTime(wrapperReleaseDate, wrapperReleaseTime); } struct tm wrapperGetBuildTime() { return getInfoTime(wrapperBuildDate, wrapperBuildTime); } /** * Adds default properties used to set global environment variables. * * These are done by setting properties rather than call setEnv directly * so that it will be impossible for users to override their values by * creating a "set.XXX=NNN" property in the configuration file. */ void wrapperAddDefaultProperties() { size_t bufferLen; TCHAR* buffer, *langTemp, *confDirTemp; #ifdef WIN32 int work, pos2; TCHAR pathSep = TEXT('\\'); #else TCHAR pathSep = TEXT('/'); #endif int pos; /* IMPORTANT - If any new values are added here, this work buffer length may need to be calculated differently. */ bufferLen = 1; bufferLen = __max(bufferLen, _tcslen(TEXT("set.WRAPPER_LANG=")) + 3 + 1); bufferLen = __max(bufferLen, _tcslen(TEXT("set.WRAPPER_PID=")) + 10 + 1); /* 32-bit PID would be max of 10 characters */ bufferLen = __max(bufferLen, _tcslen(TEXT("set.WRAPPER_BITS=")) + _tcslen(wrapperBits) + 1); bufferLen = __max(bufferLen, _tcslen(TEXT("set.WRAPPER_ARCH=")) + _tcslen(wrapperArch) + 1); bufferLen = __max(bufferLen, _tcslen(TEXT("set.WRAPPER_OS=")) + _tcslen(wrapperOS) + 1); bufferLen = __max(bufferLen, _tcslen(TEXT("set.WRAPPER_HOSTNAME=")) + _tcslen(wrapperData->hostName) + 1); bufferLen = __max(bufferLen, _tcslen(TEXT("set.WRAPPER_HOST_NAME=")) + _tcslen(wrapperData->hostName) + 1); if (wrapperData->confDir == NULL) { if (_tcsrchr(wrapperData->argConfFile, pathSep) != NULL) { pos = (int)(_tcsrchr(wrapperData->argConfFile, pathSep) - wrapperData->argConfFile); } else { pos = -1; } #ifdef WIN32 if (_tcsrchr(wrapperData->argConfFile, TEXT('/')) != NULL) { pos2 = (int)(_tcsrchr(wrapperData->argConfFile, TEXT('/')) - wrapperData->argConfFile); } else { pos2 = -1; } pos = __max(pos, pos2); #endif if (pos == -1) { confDirTemp = malloc(sizeof(TCHAR) * 2); if (!confDirTemp) { outOfMemory(TEXT("WADP"), 1); return; } _tcsncpy(confDirTemp, TEXT("."), 2); } else if (pos == 0) { confDirTemp = malloc(sizeof(TCHAR) * 2); if (!confDirTemp) { outOfMemory(TEXT("WADP"), 2); return; } _sntprintf(confDirTemp, 2, TEXT("%c"), pathSep); } else { confDirTemp = malloc(sizeof(TCHAR) * (pos + 1)); if (!confDirTemp) { outOfMemory(TEXT("WADP"), 3); return; } _tcsncpy(confDirTemp, wrapperData->argConfFile, pos); confDirTemp[pos] = TEXT('\0'); } #ifdef WIN32 /* Get buffer size, including '\0' */ work = GetFullPathName(confDirTemp, 0, NULL, NULL); if (!work) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the conf directory: %s"), getLastErrorText()); free(confDirTemp); return; } wrapperData->confDir = malloc(sizeof(TCHAR) * work); if (!wrapperData->confDir) { outOfMemory(TEXT("WADP"), 4); free(confDirTemp); return; } if (!GetFullPathName(confDirTemp, work, wrapperData->confDir, NULL)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the conf directory: %s"), getLastErrorText()); free(confDirTemp); return; } #else /* The solaris implementation of realpath will return a relative path if a relative * path is provided. We always need an abosulte path here. So build up one and * then use realpath to remove any .. or other relative references. */ wrapperData->confDir = malloc(sizeof(TCHAR) * (PATH_MAX + 1)); if (!wrapperData->confDir) { outOfMemory(TEXT("WADP"), 5); free(confDirTemp); return; } if (_trealpathN(confDirTemp, wrapperData->confDir, PATH_MAX + 1) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the original working directory: %s"), getLastErrorText()); free(confDirTemp); return; } #endif setEnv(TEXT("WRAPPER_CONF_DIR"), wrapperData->confDir, ENV_SOURCE_APPLICATION); free(confDirTemp); } buffer = malloc(sizeof(TCHAR) * bufferLen); if (!buffer) { outOfMemory(TEXT("WADP"), 1); return; } langTemp = _tgetenv(TEXT("LANG")); if ((langTemp == NULL) || (_tcslen(langTemp) == 0)) { _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_LANG=en")); } else { #ifdef WIN32 _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_LANG=%.2s"), langTemp); #else _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_LANG=%.2S"), langTemp); #endif } #if !defined(WIN32) && defined(UNICODE) if (langTemp) { free(langTemp); } #endif addPropertyPair(properties, NULL, 0, buffer, TRUE, FALSE, TRUE); _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_PID=%d"), wrapperData->wrapperPID); addPropertyPair(properties, NULL, 0, buffer, TRUE, FALSE, TRUE); _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_BITS=%s"), wrapperBits); addPropertyPair(properties, NULL, 0, buffer, TRUE, FALSE, TRUE); _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_ARCH=%s"), wrapperArch); addPropertyPair(properties, NULL, 0, buffer, TRUE, FALSE, TRUE); _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_OS=%s"), wrapperOS); addPropertyPair(properties, NULL, 0, buffer, TRUE, FALSE, TRUE); _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_HOSTNAME=%s"), wrapperData->hostName); addPropertyPair(properties, NULL, 0, buffer, TRUE, FALSE, TRUE); _sntprintf(buffer, bufferLen, TEXT("set.WRAPPER_HOST_NAME=%s"), wrapperData->hostName); addPropertyPair(properties, NULL, 0, buffer, TRUE, FALSE, TRUE); #ifdef WIN32 addPropertyPair(properties, NULL, 0, TEXT("set.WRAPPER_FILE_SEPARATOR=\\"), TRUE, FALSE, TRUE); addPropertyPair(properties, NULL, 0, TEXT("set.WRAPPER_PATH_SEPARATOR=;"), TRUE, FALSE, TRUE); #else addPropertyPair(properties, NULL, 0, TEXT("set.WRAPPER_FILE_SEPARATOR=/"), TRUE, FALSE, TRUE); addPropertyPair(properties, NULL, 0, TEXT("set.WRAPPER_PATH_SEPARATOR=:"), TRUE, FALSE, TRUE); #endif free(buffer); } /** * This function is here to help Community Edition users who are attempting * to generate a hostId. */ int showHostIds(int logLevel) { log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("The Community Edition of the Java Service Wrapper does not implement\nHostIds.")); log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("If you have requested a trial license, or purchased a license, you\nmay be looking for the Standard or Professional Editions of the Java\nService Wrapper. They can be downloaded here:")); log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT(" http://wrapper.tanukisoftware.com/download")); log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("")); return FALSE; } /** * Loads the current environment into a table so we can debug it later. * * @return TRUE if there were problems, FALSE if successful. */ int loadEnvironment() { size_t len; TCHAR *sourcePair; TCHAR *pair; TCHAR *equal; TCHAR *name; TCHAR *value; #ifdef WIN32 LPTCH lpvEnv; LPTSTR lpszVariable; #else /* The compiler won't let us reverence environ directly in the for loop on OSX because it is actually a function. */ char **environment = environ; int i; #endif #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Loading Environment...")); #endif #ifdef WIN32 lpvEnv = GetEnvironmentStrings(); if (!lpvEnv) { _tprintf(TEXT("GetEnvironmentStrings failed (%s)\n"), getLastErrorText()); return TRUE; } lpszVariable = (LPTSTR)lpvEnv; while (lpszVariable[0] != '\0') { sourcePair = lpszVariable; #else i = 0; while (environment[i]) { len = mbstowcs(NULL, environment[i], MBSTOWCS_QUERY_LENGTH); if (len == (size_t)-1) { /* Invalid string. Skip. */ } else { sourcePair = malloc(sizeof(TCHAR) * (len + 1)); if (!sourcePair) { outOfMemory(TEXT("LE"), 1); _tprintf(TEXT(" Invalid character string: %s (%s)\n"), environment[i], getLastErrorText()); return TRUE; } mbstowcs(sourcePair, environment[i], len + 1); sourcePair[len] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ #endif len = _tcslen(sourcePair); /* We need a copy of the variable pair so we can split it. */ pair = malloc(sizeof(TCHAR) * (len + 1)); if (!pair) { outOfMemory(TEXT("LE"), 1); #ifndef WIN32 free(sourcePair); #endif return TRUE; } _sntprintf(pair, len + 1, TEXT("%s"), sourcePair); equal = _tcschr(pair, TEXT('=')); if (equal) { name = pair; value = &(equal[1]); equal[0] = TEXT('\0'); if (_tcslen(name) <= 0) { name = NULL; } if (_tcslen(value) <= 0) { value = NULL; } /* It is possible that the name was empty. */ if (name) { setEnv(name, value, ENV_SOURCE_PARENT); } } free(pair); #ifdef WIN32 lpszVariable += len + 1; #else free(sourcePair); } i++; #endif } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Loading Environment complete.")); #endif return FALSE; } /** * Updates a string value by making a copy of the original. Any old value is * first freed. */ void updateStringValue(TCHAR **ptr, const TCHAR *value) { if (*ptr != NULL) { free(*ptr); *ptr = NULL; } if (value != NULL) { *ptr = malloc(sizeof(TCHAR) * (_tcslen(value) + 1)); if (!(*ptr)) { outOfMemory(TEXT("USV"), 1); /* TODO: This is pretty bad. Not sure how to recover... */ } else { _tcsncpy(*ptr, value, _tcslen(value) + 1); } } } #ifndef WIN32 /* UNIX */ int getSignalMode(const TCHAR *modeName, int defaultMode) { if (!modeName) { return defaultMode; } if (strcmpIgnoreCase(modeName, TEXT("IGNORE")) == 0) { return WRAPPER_SIGNAL_MODE_IGNORE; } else if (strcmpIgnoreCase(modeName, TEXT("RESTART")) == 0) { return WRAPPER_SIGNAL_MODE_RESTART; } else if (strcmpIgnoreCase(modeName, TEXT("SHUTDOWN")) == 0) { return WRAPPER_SIGNAL_MODE_SHUTDOWN; } else if (strcmpIgnoreCase(modeName, TEXT("FORWARD")) == 0) { return WRAPPER_SIGNAL_MODE_FORWARD; } else { return defaultMode; } } /** * Return FALSE if successful, TRUE if there were problems. */ int wrapperBuildUnixDaemonInfo() { if (!wrapperData->configured) { /** Get the daemonize flag. */ wrapperData->daemonize = getBooleanProperty(properties, TEXT("wrapper.daemonize"), FALSE); /** Configure the HUP signal handler. */ wrapperData->signalHUPMode = getSignalMode(getStringProperty(properties, TEXT("wrapper.signal.mode.hup"), NULL), WRAPPER_SIGNAL_MODE_FORWARD); /** Configure the USR1 signal handler. */ wrapperData->signalUSR1Mode = getSignalMode(getStringProperty(properties, TEXT("wrapper.signal.mode.usr1"), NULL), WRAPPER_SIGNAL_MODE_FORWARD); /** Configure the USR2 signal handler. */ wrapperData->signalUSR2Mode = getSignalMode(getStringProperty(properties, TEXT("wrapper.signal.mode.usr2"), NULL), WRAPPER_SIGNAL_MODE_FORWARD); } return FALSE; } #endif /** * Dumps the table of environment variables, and their sources. * * @param logLevel Level at which to log the output. */ void dumpEnvironment(int logLevel) { EnvSrc *envSrc; TCHAR *envVal; log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("Environment variables (Source | Name=Value) BEGIN:")); envSrc = baseEnvSrc; while (envSrc) { envVal = _tgetenv(envSrc->name); log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT(" %c%c%c%c%c | %s=%s"), (envSrc->source & ENV_SOURCE_PARENT ? TEXT('P') : TEXT('-')), #ifdef WIN32 (envSrc->source & ENV_SOURCE_REG_SYSTEM ? TEXT('S') : TEXT('-')), (envSrc->source & ENV_SOURCE_REG_ACCOUNT ? TEXT('A') : TEXT('-')), #else TEXT('-'), TEXT('-'), #endif (envSrc->source & ENV_SOURCE_APPLICATION ? TEXT('W') : TEXT('-')), (envSrc->source & ENV_SOURCE_CONFIG ? TEXT('C') : TEXT('-')), envSrc->name, (envVal ? envVal : TEXT("")) ); #if !defined(WIN32) && defined(UNICODE) if (envVal) { free(envVal); } #endif envSrc = envSrc->next; } log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("Environment variables END:")); log_printf(WRAPPER_SOURCE_WRAPPER, logLevel, TEXT("")); } #ifdef WIN32 /** * Check if the Wrapper is running under cygwin terminal. * I'm looking for the environment variable TERM to be equal to "xterm". * I tried with OSTYPE and MACHTYPE, but _tgetenv always returns NULL. * @return TRUE if under cygwin, otherwise returns FALSE */ int isCygwin() { TCHAR *osType; int retVal = FALSE; osType = _tgetenv(TEXT("TERM")); if ((osType != NULL) && (_tcscmp(osType, TEXT("xterm")) == 0)) { retVal = TRUE; } return retVal; } #endif void wrapperLoadLoggingProperties(int preload) { const TCHAR *logfilePath; int logfileRollMode; int underCygwin = FALSE; setLogPropertyWarnings(properties, !preload); setLogPropertyWarningLogLevel(properties, getLogLevelForName(getStringProperty(properties, TEXT("wrapper.property_warning.loglevel"), TEXT("WARN")))); setLogWarningThreshold(getIntProperty(properties, TEXT("wrapper.log.warning.threshold"), 0)); wrapperData->logLFDelayThreshold = propIntMax(propIntMin(getIntProperty(properties, TEXT("wrapper.log.lf_delay.threshold"), 500), 3600000), 0); logfilePath = getFileSafeStringProperty(properties, TEXT("wrapper.logfile"), TEXT("wrapper.log")); setLogfilePath(logfilePath, wrapperData->workingDir, preload); logfileRollMode = getLogfileRollModeForName(getStringProperty(properties, TEXT("wrapper.logfile.rollmode"), TEXT("SIZE"))); if (logfileRollMode == ROLL_MODE_UNKNOWN) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("wrapper.logfile.rollmode invalid. Disabling log file rolling.")); logfileRollMode = ROLL_MODE_NONE; } else if (logfileRollMode == ROLL_MODE_DATE) { if (!_tcsstr(logfilePath, ROLL_MODE_DATE_TOKEN)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("wrapper.logfile must contain \"%s\" for a roll mode of DATE. Disabling log file rolling."), ROLL_MODE_DATE_TOKEN); logfileRollMode = ROLL_MODE_NONE; } } setLogfileRollMode(logfileRollMode); /* Load log file format */ setLogfileFormat(getStringProperty(properties, TEXT("wrapper.logfile.format"), LOG_FORMAT_LOGFILE_DEFAULT)); /* Load log file log level */ setLogfileLevel(getStringProperty(properties, TEXT("wrapper.logfile.loglevel"), TEXT("INFO"))); /* Load max log filesize log level */ setLogfileMaxFileSize(getStringProperty(properties, TEXT("wrapper.logfile.maxsize"), TEXT("0"))); /* Load log files level */ setLogfileMaxLogFiles(getIntProperty(properties, TEXT("wrapper.logfile.maxfiles"), 0)); /* Load log file purge pattern */ setLogfilePurgePattern(getFileSafeStringProperty(properties, TEXT("wrapper.logfile.purge.pattern"), TEXT(""))); /* Load log file purge sort */ setLogfilePurgeSortMode(loggerFileGetSortMode(getStringProperty(properties, TEXT("wrapper.logfile.purge.sort"), TEXT("TIMES")))); /* Get the close timeout. */ wrapperData->logfileCloseTimeout = propIntMax(propIntMin(getIntProperty(properties, TEXT("wrapper.logfile.close.timeout"), getIntProperty(properties, TEXT("wrapper.logfile.inactivity.timeout"), 1)), 3600), -1); setLogfileAutoClose(wrapperData->logfileCloseTimeout == 0); /* Get the flush timeout. */ wrapperData->logfileFlushTimeout = propIntMax(propIntMin(getIntProperty(properties, TEXT("wrapper.logfile.flush.timeout"), 1), 3600), 0); setLogfileAutoFlush(wrapperData->logfileFlushTimeout == 0); /* Load console format */ setConsoleLogFormat(getStringProperty(properties, TEXT("wrapper.console.format"), LOG_FORMAT_CONSOLE_DEFAULT)); setConsoleLogLevel(getStringProperty(properties, TEXT("wrapper.console.loglevel"), TEXT("INFO"))); #ifdef WIN32 /* check if the current instance of the Wrapper is running under Cygwin */ underCygwin = isCygwin(); #endif /* Load the console flush flag. */ setConsoleFlush(getBooleanProperty(properties, TEXT("wrapper.console.flush"), FALSE || underCygwin)); #ifdef WIN32 /* Load the console direct flag. */ setConsoleDirect(getBooleanProperty(properties, TEXT("wrapper.console.direct"), TRUE)); #endif /* Load the console loglevel targets. */ setConsoleFatalToStdErr(getBooleanProperty(properties, TEXT("wrapper.console.fatal_to_stderr"), TRUE)); setConsoleErrorToStdErr(getBooleanProperty(properties, TEXT("wrapper.console.error_to_stderr"), TRUE)); setConsoleWarnToStdErr(getBooleanProperty(properties, TEXT("wrapper.console.warn_to_stderr"), FALSE)); /* Load syslog log level */ setSyslogLevel(getStringProperty(properties, TEXT("wrapper.syslog.loglevel"), TEXT("NONE"))); /* Load syslog split messages flag. */ setSyslogSplitMessages(getBooleanProperty(properties, TEXT("wrapper.syslog.split_messages"), FALSE)); #ifndef WIN32 /* Load syslog facility */ setSyslogFacility(getStringProperty(properties, TEXT("wrapper.syslog.facility"), TEXT("USER"))); #endif /* Load syslog event source name */ setSyslogEventSourceName(getStringProperty(properties, TEXT("wrapper.syslog.ident"), getStringProperty(properties, TEXT("wrapper.name"), getStringProperty(properties, TEXT("wrapper.ntservice.name"), TEXT("wrapper"))))); /* Register the syslog message file if syslog is enabled */ if (getSyslogLevelInt() < LEVEL_NONE) { registerSyslogMessageFile(); } /* Get the debug status (Property is deprecated but flag is still used) */ wrapperData->isDebugging = getBooleanProperty(properties, TEXT("wrapper.debug"), FALSE); if (wrapperData->isDebugging) { /* For backwards compatability */ setConsoleLogLevelInt(LEVEL_DEBUG); setLogfileLevelInt(LEVEL_DEBUG); } else { if (getLowLogLevel() <= LEVEL_DEBUG) { wrapperData->isDebugging = TRUE; } } } /** * Load the configuration. * * @param preload TRUE if the configuration is being preloaded. * * Return TRUE if there were any problems. */ int wrapperLoadConfigurationProperties(int preload) { int i; int firstCall; #ifdef WIN32 int work; int defaultUMask; #else mode_t defaultUMask; #endif const TCHAR* prop; /* Unless this is the first call, we need to dispose the previous properties object. */ if (properties) { firstCall = FALSE; disposeProperties(properties); properties = NULL; } else { firstCall = TRUE; if (wrapperData->originalWorkingDir) { free(wrapperData->originalWorkingDir); } /* This is the first time, so preserve the working directory. */ #ifdef WIN32 /* Get buffer size, including '\0' */ work = GetFullPathName(TEXT("."), 0, NULL, NULL); if (!work) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the original working directory: %s"), getLastErrorText()); return TRUE; } wrapperData->originalWorkingDir = malloc(sizeof(TCHAR) * work); if (!wrapperData->originalWorkingDir) { outOfMemory(TEXT("WLCP"), 3); return TRUE; } if (!GetFullPathName(TEXT("."), work, wrapperData->originalWorkingDir, NULL)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the original working directory: %s"), getLastErrorText()); return TRUE; } #else /* The solaris implementation of realpath will return a relative path if a relative * path is provided. We always need an abosulte path here. So build up one and * then use realpath to remove any .. or other relative references. */ wrapperData->originalWorkingDir = malloc(sizeof(TCHAR) * (PATH_MAX + 1)); if (!wrapperData->originalWorkingDir) { outOfMemory(TEXT("WLCP"), 4); return TRUE; } if (_trealpathN(TEXT("."), wrapperData->originalWorkingDir, PATH_MAX + 1) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the original working directory: %s"), getLastErrorText()); return TRUE; } #endif if (wrapperData->configFile) { free(wrapperData->configFile); } /* This is the first time, so preserve the full canonical location of the * configuration file. */ #ifdef WIN32 work = GetFullPathName(wrapperData->argConfFile, 0, NULL, NULL); if (!work) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the full path of the configuration file, %s: %s"), wrapperData->argConfFile, getLastErrorText()); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Current working directory is: %s"), wrapperData->originalWorkingDir); return TRUE; } wrapperData->configFile = malloc(sizeof(TCHAR) * work); if (!wrapperData->configFile) { outOfMemory(TEXT("WLCP"), 1); return TRUE; } if (!GetFullPathName(wrapperData->argConfFile, work, wrapperData->configFile, NULL)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the full path of the configuration file, %s: %s"), wrapperData->argConfFile, getLastErrorText()); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT( "Current working directory is: %s"), wrapperData->originalWorkingDir); return TRUE; } #else /* The solaris implementation of realpath will return a relative path if a relative * path is provided. We always need an abosulte path here. So build up one and * then use realpath to remove any .. or other relative references. */ wrapperData->configFile = malloc(sizeof(TCHAR) * (PATH_MAX + 1)); if (!wrapperData->configFile) { outOfMemory(TEXT("WLCP"), 2); return TRUE; } if (_trealpathN(wrapperData->argConfFile, wrapperData->configFile, PATH_MAX + 1) == NULL) { /* Most likely the file does not exist. The wrapperData->configFile has the first * file that could not be found. May not be the config file directly if symbolic * links are involved. */ if (wrapperData->argConfFileDefault) { /* The output buffer is likely to contain undefined data. * To be on the safe side and in order to report the error * below correctly we need to override the data first.*/ _sntprintf(wrapperData->configFile, PATH_MAX + 1, TEXT("%s"), wrapperData->argConfFile); /* This was the default config file name. We know that the working directory * could be resolved so the problem must be that the default config file does * not exist. This problem will be reported later and the wrapperData->configFile * variable will have the correct full path. * Fall through for now and the user will get a better error later. */ } else { if (!preload) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT( "Unable to open configuration file: %s (%s)\n Current working directory: %s"), wrapperData->argConfFile, getLastErrorText(), wrapperData->originalWorkingDir); } return TRUE; } } #endif } /* Create a Properties structure. */ properties = createProperties(); if (!properties) { return TRUE; } setLogPropertyWarnings(properties, !preload); wrapperAddDefaultProperties(); /* The argument prior to the argBase will be the configuration file, followed * by 0 or more command line properties. The command line properties need to be * loaded first, followed by the configuration file. */ if (strcmpIgnoreCase(wrapperData->argCommand, TEXT("-translate")) != 0) { for (i = 0; i < wrapperData->argCount; i++) { if (addPropertyPair(properties, NULL, 0, wrapperData->argValues[i], TRUE, TRUE, FALSE)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("The argument '%s' is not a valid property name-value pair."), wrapperData->argValues[i]); return TRUE; } } } /* Now load the configuration file. * When this happens, the working directory MUST be set to the original working dir. */ #ifdef WIN32 if (loadProperties(properties, wrapperData->configFile, preload, wrapperData->argCommand, wrapperData->originalWorkingDir, wrapperData->isDebugging)) { #else if (loadProperties(properties, wrapperData->configFile, (preload | wrapperData->daemonize), wrapperData->argCommand, wrapperData->originalWorkingDir, wrapperData->isDebugging)) { #endif /* File not found. */ /* If this was a default file name then we don't want to show this as * an error here. It will be handled by the caller. */ /* Debug is not yet available as the config file is not yet loaded. */ if ((!preload) && (!wrapperData->argConfFileDefault)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Failed to load configuration: %s"), wrapperData->configFile); } return TRUE; } /* Config file found. */ wrapperData->argConfFileFound = TRUE; if (firstCall) { /* If the working dir was configured, we need to extract it and preserve its value. * This must be done after the configuration has been completely loaded. */ prop = getStringProperty(properties, TEXT("wrapper.working.dir"), TEXT(".")); if (prop && (_tcslen(prop) > 0)) { if (wrapperData->workingDir) { free(wrapperData->workingDir); } #ifdef WIN32 work = GetFullPathName(prop, 0, NULL, NULL); if (!work) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the working directory %s: %s"), prop, getLastErrorText()); return TRUE; } wrapperData->workingDir = malloc(sizeof(TCHAR) * work); if (!wrapperData->workingDir) { outOfMemory(TEXT("WLCP"), 5); return TRUE; } if (!GetFullPathName(prop, work, wrapperData->workingDir, NULL)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the working directory %s: %s"), prop, getLastErrorText()); return TRUE; } #else /* The solaris implementation of realpath will return a relative path if a relative * path is provided. We always need an abosulte path here. So build up one and * then use realpath to remove any .. or other relative references. */ wrapperData->workingDir = malloc(sizeof(TCHAR) * (PATH_MAX + 1)); if (!wrapperData->workingDir) { outOfMemory(TEXT("WLCP"), 6); return TRUE; } if (_trealpathN(prop, wrapperData->workingDir, PATH_MAX + 1) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the working directory %s: %s"), prop, getLastErrorText()); return TRUE; } #endif } } #ifdef _DEBUG /* Display the active properties */ _tprintf(TEXT("Debug Configuration Properties:\n")); dumpProperties(properties); #endif /* Now that the configuration is loaded, we need to update the working directory if the user specified one. * This must be done now so that anything that references the working directory, including the log file * and language pack locations will work correctly. */ if (wrapperData->workingDir && wrapperSetWorkingDir(wrapperData->workingDir, !preload)) { return TRUE; } if (wrapperData->umask == -1) { /** Get the umask value for the various files. */ #ifdef WIN32 defaultUMask = _umask(0); _umask(defaultUMask); #else defaultUMask = umask((mode_t)0); umask(defaultUMask); #endif wrapperData->umask = getIntProperty(properties, TEXT("wrapper.umask"), defaultUMask); } wrapperData->javaUmask = getIntProperty(properties, TEXT("wrapper.java.umask"), wrapperData->umask); wrapperData->pidFileUmask = getIntProperty(properties, TEXT("wrapper.pidfile.umask"), wrapperData->umask); wrapperData->lockFileUmask = getIntProperty(properties, TEXT("wrapper.lockfile.umask"), wrapperData->umask); wrapperData->javaPidFileUmask = getIntProperty(properties, TEXT("wrapper.java.pidfile.umask"), wrapperData->umask); wrapperData->javaIdFileUmask = getIntProperty(properties, TEXT("wrapper.java.idfile.umask"), wrapperData->umask); wrapperData->statusFileUmask = getIntProperty(properties, TEXT("wrapper.statusfile.umask"), wrapperData->umask); wrapperData->javaStatusFileUmask = getIntProperty(properties, TEXT("wrapper.java.statusfile.umask"), wrapperData->umask); wrapperData->anchorFileUmask = getIntProperty(properties, TEXT("wrapper.anchorfile.umask"), wrapperData->umask); setLogfileUmask(getIntProperty(properties, TEXT("wrapper.logfile.umask"), wrapperData->umask)); #ifndef WIN32 /** If in the first call here and the wrapper will deamonize, then we don't need * to proceed any further anymore as the properties will be loaded properly at * the second time... */ if ((firstCall == TRUE) && (!wrapperBuildUnixDaemonInfo()) && wrapperData->daemonize) { return FALSE; } #endif /* Load the configuration. */ if ((strcmpIgnoreCase(wrapperData->argCommand, TEXT("-translate")) != 0) && loadConfiguration()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Problem loading wrapper configuration file: %s"), wrapperData->configFile); return TRUE; } return FALSE; } void wrapperGetCurrentTime(struct timeb *timeBuffer) { #ifdef WIN32 ftime(timeBuffer); #else struct timeval tv; gettimeofday(&tv, NULL); timeBuffer->time = (time_t)tv.tv_sec; timeBuffer->millitm = (unsigned short)(tv.tv_usec / 1000); #endif } /** * This function stops the pipes (quite in a brutal way) */ void protocolStopServerPipe() { if (protocolActiveServerPipeIn != INVALID_HANDLE_VALUE) { #ifdef WIN32 CloseHandle(protocolActiveServerPipeIn); #else close(protocolActiveServerPipeIn); #endif protocolActiveServerPipeIn = INVALID_HANDLE_VALUE; log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_INFO, TEXT("backend pipe closed.")); } if (protocolActiveServerPipeOut != INVALID_HANDLE_VALUE) { #ifdef WIN32 CloseHandle(protocolActiveServerPipeOut); #else close(protocolActiveServerPipeOut); #endif protocolActiveServerPipeOut = INVALID_HANDLE_VALUE; log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_INFO, TEXT("backend pipe closed.")); } } /** * There is no difference between closing a socket IPv4 vs a socket IPv6 */ void protocolStopServerSocket() { int rc; /* Close the socket. */ if (protocolActiveServerSD != INVALID_SOCKET) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("closing backend server.")); } #ifdef WIN32 rc = closesocket(protocolActiveServerSD); #else /* UNIX */ rc = close(protocolActiveServerSD); #endif if (rc == SOCKET_ERROR) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("server socket close failed. (%d)"), wrapperGetLastError()); } } protocolActiveServerSD = INVALID_SOCKET; } wrapperData->actualPort = 0; } void protocolStopServer() { if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) { protocolStopServerPipe(); } else { protocolStopServerSocket(); } } int protocolActiveServerPipeStarted = FALSE; int protocolStartServerPipe() { size_t pipeNameLen; TCHAR *pipeName; #ifdef WIN32 pipeNameLen = 17 + 10 + 1 + 10 + 3; #else pipeNameLen = 12 + 10 + 1 + 10 + 3; #endif pipeName = malloc(sizeof(TCHAR) * (pipeNameLen + 1)); if (!pipeName) { outOfMemory(TEXT("PSSP"), 1); return TRUE; } #ifdef WIN32 _sntprintf(pipeName, pipeNameLen, TEXT("\\\\.\\pipe\\wrapper-%d-%d-out"), wrapperData->wrapperPID, wrapperData->jvmRestarts + 1); if ((protocolActiveServerPipeOut = CreateNamedPipe(pipeName, PIPE_ACCESS_OUTBOUND,/* + FILE_FLAG_FIRST_PIPE_INSTANCE, */ PIPE_TYPE_MESSAGE | /* message type pipe */ PIPE_READMODE_MESSAGE | /* message-read mode */ PIPE_NOWAIT, /* nonblocking mode */ 1, /* only allow 1 connection at a time */ 32768, 32768, 0, NULL)) == INVALID_HANDLE_VALUE) { #else _sntprintf(pipeName, pipeNameLen, TEXT("/tmp/wrapper-%d-%d-out"), wrapperData->wrapperPID, wrapperData->jvmRestarts + 1); if (_tmkfifo(pipeName, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) == INVALID_HANDLE_VALUE) { #endif log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("Unable to create backend pipe: %s"), getLastErrorText()); free(pipeName); return TRUE; } if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("server listening on pipe %s."), pipeName); } #ifdef WIN32 _sntprintf(pipeName, pipeNameLen, TEXT("\\\\.\\pipe\\wrapper-%d-%d-in"), wrapperData->wrapperPID, wrapperData->jvmRestarts + 1); if ((protocolActiveServerPipeIn = CreateNamedPipe(pipeName, PIPE_ACCESS_INBOUND,/* + FILE_FLAG_FIRST_PIPE_INSTANCE,*/ PIPE_TYPE_MESSAGE | /* message type pipe */ PIPE_READMODE_MESSAGE | /* message-read mode*/ PIPE_NOWAIT, /* nonblocking mode*/ 1, 32768, 32768, 0, NULL)) == INVALID_HANDLE_VALUE) { #else _sntprintf(pipeName, pipeNameLen, TEXT("/tmp/wrapper-%d-%d-in"), wrapperData->wrapperPID, wrapperData->jvmRestarts + 1); if (_tmkfifo(pipeName, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) == INVALID_HANDLE_VALUE) { #endif log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("Unable to create backend pipe: %s"), getLastErrorText()); free(pipeName); return TRUE; } if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("server listening on pipe %s."), pipeName); } protocolActiveServerPipeStarted = TRUE; free(pipeName); return FALSE; } #ifdef WIN32 /** * This function doesn't exist on Windows. Similar to inet_ntop that you can find on unix. * Convert IPv4 and IPv6 addresses from binary to text form * @param af The family type (AF_INET or AF_INET6) * @param src Network address structure * @param dst Pointer where to write the text form of the address * @return On success, inet_ntop() returns a non-NULL pointer to dst. NULL is returned if there was an error. */ const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt) { int result; struct sockaddr_in6 addr6; struct sockaddr_in addr4; if (af == AF_INET) { memset(&addr4, 0, sizeof(struct sockaddr_in)); memcpy(&(addr4.sin_addr), src, sizeof(addr4.sin_addr)); addr4.sin_family = af; /* here is the function to return a TCHAR. I keep it commented out just as a note */ /* result = WSAAddressToString((struct sockaddr*) &addr4, sizeof(struct sockaddr_in), 0, dst, (LPDWORD) &cnt); */ result = getnameinfo((struct sockaddr *)&addr4, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST); } else { memset(&addr6, 0, sizeof(struct sockaddr_in)); memcpy(&(addr6.sin6_addr), src, sizeof(addr6.sin6_addr)); addr6.sin6_family = af; /* here is the function to return a TCHAR. I keep it commented out just as a note */ /* result = WSAAddressToString((struct sockaddr*) &addr6, sizeof(struct sockaddr_in6), 0, dst, (LPDWORD) &cnt); */ result = getnameinfo((struct sockaddr *)&addr6, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST); } if (result != 0) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("getnameinfo failed (%d): (%s)"), result, getLastErrorText()); return NULL; } return dst; } /** * This function doesn't exist on Windows. Similar to inet_pton that you can find on unix. * convert IPv4 and IPv6 addresses from text to binary form * @param af The family type (AF_INET or AF_INET6) * @param src The adress in text * @param dst Pointer where to write the binary form of the address * @return FALSE if no error. */ int inet_pton(int af, const char *src, void *dst) { struct addrinfo hints; struct addrinfo *res, *ressave; int result; int i = 0; struct sockaddr_in6 *sockaddr_ipv6; struct sockaddr_in *sockaddr_ipv4; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = af; result = getaddrinfo(src, NULL, &hints, &res); if (result != 0) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("getaddrinfo failed (%d): (%s)"), result, getLastErrorText()); return TRUE; } ressave = res; while (res) { switch (res->ai_family) { case AF_INET: sockaddr_ipv4 = (struct sockaddr_in *) res->ai_addr; memcpy(dst, &sockaddr_ipv4->sin_addr, sizeof(struct in_addr)); result = FALSE; break; case AF_INET6: sockaddr_ipv6 = (struct sockaddr_in6 *) res->ai_addr; memcpy(dst, &sockaddr_ipv6->sin6_addr, sizeof(struct in6_addr)); result = FALSE; break; default: log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("Ignore unsupported family type: %d"), res->ai_family); break; } res = res->ai_next; } freeaddrinfo(ressave); return result; } #endif /** * Start server using a socket * @param IPv4 if true then we use IPv4, otherwise we use IPv6 * @return FALSE if socket is created successfully. For some specific error, returns WRAPPER_BACKEND_ERROR_NEXT, for all the other errors returns TRUE */ int protocolStartServerSocket(int IPv4) { struct sockaddr_in addr_srv4; struct sockaddr_in6 addr_srv6; int rc; int port; int fixedPort; #ifdef UNICODE char* tempAddress; size_t len; #endif /*int optVal;*/ #ifdef WIN32 u_long dwNoBlock = TRUE; #endif /* Create the server socket. */ if (IPv4) { protocolActiveServerSD = socket(AF_INET, SOCK_STREAM, 0); } else { protocolActiveServerSD = socket(AF_INET6, SOCK_STREAM, 0); } if (protocolActiveServerSD == INVALID_SOCKET) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("server socket creation failed. (%s)"), getLastErrorText()); return WRAPPER_BACKEND_ERROR_NEXT; } /* Make sure the socket is reused. */ /* We actually do not want to do this as it makes it possible for more than one Wrapper * instance to bind to the same port. The second instance succeeds to bind, but any * attempts to connect to that port will go to the first Wrapper. This would of course * cause attempts to launch the second JVM to fail. * Leave this code here as a future development note. optVal = 1; #ifdef WIN32 if (setsockopt(protocolActiveServerSD, SOL_SOCKET, SO_REUSEADDR, (TCHAR *)&optVal, sizeof(optVal)) < 0) { #else if (setsockopt(protocolActiveServerSD, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(optVal)) < 0) { #endif log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, "server socket SO_REUSEADDR failed. (%s)", getLastErrorText()); wrapperProtocolClose(); protocolStopServer(); return; } */ /* Make the socket non-blocking */ #ifdef WIN32 rc = ioctlsocket(protocolActiveServerSD, FIONBIO, &dwNoBlock); #else /* UNIX */ rc = fcntl(protocolActiveServerSD, F_SETFL, O_NONBLOCK); #endif if (rc == SOCKET_ERROR) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("server socket ioctlsocket failed. (%s)"), getLastErrorText()); wrapperProtocolClose(); protocolStopServer(); return TRUE; } /* If a port was specified in the configuration file then we want to * try to use that port or find the next available port. If 0 was * specified, then we will silently start looking for an available * port starting at 32000. */ port = wrapperData->port; if (port <= 0) { port = wrapperData->portMin; fixedPort = FALSE; } else { fixedPort = TRUE; } tryagain: /* Cleanup the socket first */ if (IPv4) { memset(&addr_srv4, 0, sizeof(addr_srv4)); addr_srv4.sin_family = AF_INET; addr_srv4.sin_port = htons((u_short)port); } else { memset(&addr_srv6, 0, sizeof(addr_srv6)); addr_srv6.sin6_family = AF_INET6; addr_srv6.sin6_flowinfo = 0; /* htons switch the 2 bytes. For example: 32000 in binary: 1111101 00000000 After swap: 00000000 1111101 which is 125 in decimal */ addr_srv6.sin6_port = htons((u_short)port); } if (wrapperData->portAddress == NULL) { /* the user hasn't defined any address, so we use the loopback address */ if (IPv4) { addr_srv4.sin_addr.s_addr = inet_addr(LOOPBACK_IPv4); } else { addr_srv6.sin6_addr = LOOPBACK_IPv6; } } else { #ifdef UNICODE #ifdef WIN32 len = WideCharToMultiByte(CP_OEMCP, 0, wrapperData->portAddress, -1, NULL, 0, NULL, NULL); if (len <= 0) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_WARN, TEXT("Invalid multibyte sequence in port address \"%s\" : %s"), wrapperData->portAddress, getLastErrorText()); return TRUE; } tempAddress = malloc(len); if (!tempAddress) { outOfMemory(TEXT("PSSS"), 1); return TRUE; } WideCharToMultiByte(CP_OEMCP, 0, wrapperData->portAddress, -1, tempAddress, (int)len, NULL, NULL); #else len = wcstombs(NULL, wrapperData->portAddress, 0); if (len == (size_t)-1) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_WARN, TEXT("Invalid multibyte sequence in port address \"%s\" : %s"), wrapperData->portAddress, getLastErrorText()); return TRUE; } tempAddress = malloc(len + 1); if (!tempAddress) { outOfMemory(TEXT("PSSS"), 2); return TRUE; } wcstombs(tempAddress, wrapperData->portAddress, len + 1); #endif /* convert the adress from text to binary form */ if (IPv4) { inet_pton(AF_INET, (const char *)tempAddress, &(addr_srv4.sin_addr)); } else { inet_pton(AF_INET6, (const char *)tempAddress, &(addr_srv6.sin6_addr)); } free(tempAddress); #else if (IPv4) { inet_pton(AF_INET, (const char *)wrapperData->portAddress, &(addr_srv4.sin_addr)); } else { inet_pton(AF_INET6, (const char *)wrapperData->portAddress, &(addr_srv6.sin6_addr)); } #endif } #ifdef WIN32 if (IPv4) { rc = bind(protocolActiveServerSD, (struct sockaddr FAR *)&addr_srv4, sizeof(addr_srv4)); } else { rc = bind(protocolActiveServerSD, (struct sockaddr FAR *)&addr_srv6, sizeof(addr_srv6)); } #else /* UNIX */ if (IPv4) { rc = bind(protocolActiveServerSD, (struct sockaddr *)&addr_srv4, sizeof(addr_srv4)); } else { rc = bind(protocolActiveServerSD, (struct sockaddr *)&addr_srv6, sizeof(addr_srv6)); } #endif if (rc == SOCKET_ERROR) { rc = wrapperGetLastError(); /* The specified port could not be bound. */ if ((rc == WRAPPER_EADDRINUSE) || (rc == WRAPPER_EACCES)) { /* Address in use, try looking at the next one. */ if (fixedPort) { /* The last port checked was the defined fixed port, switch to the dynamic range. */ port = wrapperData->portMin; fixedPort = FALSE; goto tryagain; } else { port++; if (port <= wrapperData->portMax) { goto tryagain; } } } /* Log an error. This is fatal, so die. */ if (wrapperData->port <= 0) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_FATAL, TEXT("unable to bind listener to any port in the range %d to %d. (%s)"), wrapperData->portMin, wrapperData->portMax, getLastErrorText()); } else { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_FATAL, TEXT("unable to bind listener port %d, or any port in the range %d to %d. (%s)"), wrapperData->port, wrapperData->portMin, wrapperData->portMax, getLastErrorText()); } wrapperStopProcess(getLastError(), TRUE); wrapperProtocolClose(); protocolStopServer(); wrapperData->exitRequested = TRUE; wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_NO; return TRUE; } /* If we got here, then we are bound to the port */ if ((wrapperData->port > 0) && (port != wrapperData->port)) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_INFO, TEXT("port %d already in use, using port %d instead."), wrapperData->port, port); } wrapperData->actualPort = port; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("server listening on port %d."), wrapperData->actualPort); } /* Tell the socket to start listening. */ rc = listen(protocolActiveServerSD, 1); if (rc == SOCKET_ERROR) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("server socket listen failed. (%d)"), wrapperGetLastError()); wrapperProtocolClose(); protocolStopServer(); return TRUE; } return FALSE; } /** * if backendType is 'auto', then it will try in this order: * - socket IPv4 * - socket IPv6 * - pipe * if backendType is 'socket', then it will try in this order: * - socket IPv4 * - socket IPv6 */ void protocolStartServer() { int useFallbackAuto = FALSE; int useFallbackSocket = FALSE; int result; if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_AUTO) { useFallbackAuto = TRUE; } if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_SOCKET) { useFallbackSocket = TRUE; } if (wrapperData->backendType & WRAPPER_BACKEND_TYPE_SOCKET_V4) { result = protocolStartServerSocket(TRUE); if (result == WRAPPER_BACKEND_ERROR_NEXT && (useFallbackAuto || useFallbackSocket)) { /* we failed to use Ipv4, so lets try with IPv6 */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Failed to start server using socket IPv4, will try with socket IPv6...")); } else if (result == FALSE) { /* success */ wrapperData->backendType = WRAPPER_BACKEND_TYPE_SOCKET_V4; return; } else { /* error message should have already be printed in protocolStartServerSocket */ } } if (wrapperData->backendType & WRAPPER_BACKEND_TYPE_SOCKET_V6) { result = protocolStartServerSocket(FALSE); if (result == WRAPPER_BACKEND_ERROR_NEXT && useFallbackAuto) { /* we failed to use Ipv6, so lets try with pipe */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Failed to start server socket IPv6, will try with Pipe...")); } else if (result == FALSE) { /* success */ wrapperData->backendType = WRAPPER_BACKEND_TYPE_SOCKET_V6; return; } else { /* error message should have already be printed in protocolStartServerSocket */ } } if ( wrapperData->backendType & WRAPPER_BACKEND_TYPE_PIPE) { result = protocolStartServerPipe(); if (result == WRAPPER_BACKEND_ERROR_NEXT && useFallbackAuto) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Failed to start server socket when trying with socket (IPv4 and IPv6) and pipe...")); } else if (result == FALSE) { /* success */ wrapperData->backendType = WRAPPER_BACKEND_TYPE_PIPE; return; } else { /* error message should have already be printed in protocolStartServerPipe */ } } /* if we reach this code, it means we couldn't create a socket or a pipe */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to start server socket.")); if (!useFallbackAuto) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("You can set wrapper.backend.type=AUTO, so the wrapper will try to connect to the JVM using ipv4, ipv6 and pipe.")); if (!useFallbackSocket) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("You can set wrapper.backend.type=SOCKET, so the wrapper will try to connect to the JVM using ipv4 and ipv6.")); } } return; } /* this functions connects the pipes once the other end is there */ void protocolOpenPipe() { #ifdef WIN32 int result; result = ConnectNamedPipe(protocolActiveServerPipeOut, NULL); if (GetLastError() == ERROR_PIPE_LISTENING) { return; } result = ConnectNamedPipe(protocolActiveServerPipeIn, NULL); if (GetLastError() == ERROR_PIPE_LISTENING) { return; } if ((result == 0) && (GetLastError() != ERROR_PIPE_CONNECTED) && (GetLastError() != ERROR_NO_DATA)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Pipe connect failed: %s"), getLastErrorText()); return; } #else size_t pipeNameLen; TCHAR *pipeName; pipeNameLen = 12 + 10 + 1 + 10 + 3; pipeName = malloc(sizeof(TCHAR) * (pipeNameLen + 1)); if (!pipeName) { outOfMemory(TEXT("PSSP"), 1); return; } _sntprintf(pipeName, pipeNameLen, TEXT("/tmp/wrapper-%d-%d-out"), wrapperData->wrapperPID, wrapperData->jvmRestarts); protocolActiveServerPipeOut = _topen(pipeName, O_WRONLY | O_NONBLOCK, S_IWUSR | S_IRUSR); if (protocolActiveServerPipeOut == INVALID_HANDLE_VALUE) { free(pipeName); return; } _sntprintf(pipeName, pipeNameLen, TEXT("/tmp/wrapper-%d-%d-in"), wrapperData->wrapperPID, wrapperData->jvmRestarts); protocolActiveServerPipeIn = _topen(pipeName, O_RDONLY | O_NONBLOCK, S_IRUSR); if (protocolActiveServerPipeIn == INVALID_HANDLE_VALUE) { free(pipeName); return; } free(pipeName); #endif protocolActiveServerPipeConnected = TRUE; } /** * @param IPv4 if true then we use IPv4, otherwise we use IPv6 */ void protocolOpenSocket(int IPv4) { struct sockaddr_in6 addr_srv6; struct sockaddr_in addr_srv4; int rc; TCHAR* socketSource; int req; #if defined(WIN32) u_long dwNoBlock = TRUE; u_long addr_srv_len; #elif (defined(HPUX) && !defined(ARCH_IA)) || defined(OSF1) || defined(IRIX) int addr_srv_len; #else socklen_t addr_srv_len; #endif SOCKET newBackendSD = INVALID_SOCKET; char straddr[256] = {0}; int port; /* Is the server socket open? */ if (protocolActiveServerSD == INVALID_SOCKET) { /* can't do anything yet. */ return; } /* Try accepting a socket. */ if (IPv4) { addr_srv_len = sizeof(addr_srv4); } else { addr_srv_len = sizeof(addr_srv6); } #ifdef WIN32 if (IPv4) { newBackendSD = accept(protocolActiveServerSD, (struct sockaddr FAR *)&addr_srv4, &addr_srv_len); } else { newBackendSD = accept(protocolActiveServerSD, (struct sockaddr FAR *)&addr_srv6, &addr_srv_len); } #else /* UNIX */ if (IPv4) { newBackendSD = accept(protocolActiveServerSD, (struct sockaddr *)&addr_srv4, &addr_srv_len); } else { newBackendSD = accept(protocolActiveServerSD, (struct sockaddr *)&addr_srv6, &addr_srv_len); } #endif if (newBackendSD == INVALID_SOCKET) { rc = wrapperGetLastError(); /* EWOULDBLOCK != EAGAIN on some platforms. */ if ((rc == WRAPPER_EWOULDBLOCK) || (rc == EAGAIN)) { /* There are no incomming sockets right now. */ return; } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("socket creation failed. (%s)"), getLastErrorText()); } return; } } /* get a human readable version of the address */ if (IPv4) { inet_ntop(AF_INET, &addr_srv4.sin_addr, straddr, sizeof(straddr)); } else { inet_ntop(AF_INET6, &addr_srv6.sin6_addr, straddr, sizeof(straddr)); } /* convert the address */ #ifdef WIN32 req = MultiByteToWideChar(CP_OEMCP, 0, straddr, -1, NULL, 0); if (req <= 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Invalid multibyte sequence in %s: %s"), TEXT("network address"), getLastErrorText()); return; } socketSource = malloc(sizeof(TCHAR) * (req + 1)); if (!socketSource) { outOfMemory(TEXT("PO"), 1); return; } MultiByteToWideChar(CP_OEMCP, 0, straddr, -1, socketSource, req + 1); #else req = mbstowcs(NULL, straddr, MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_WARN, TEXT("Invalid multibyte sequence in %s: %s"), TEXT("network address"), getLastErrorText()); return; } socketSource = malloc(sizeof(TCHAR) * (req + 1)); if (!socketSource) { outOfMemory(TEXT("PO"), 2); return; } mbstowcs(socketSource, straddr, req + 1); socketSource[req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ #endif /* Is it already open? */ if (protocolActiveBackendSD != INVALID_SOCKET) { if (IPv4) { port = ntohs(addr_srv4.sin_port); } else { port = ntohs(addr_srv6.sin6_port); } log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_WARN, TEXT("Ignoring unexpected backend socket connection from %s on port %d"), socketSource, port); free(socketSource); #ifdef WIN32 rc = closesocket(newBackendSD); #else /* UNIX */ rc = close(newBackendSD); #endif if (rc == SOCKET_ERROR) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("socket close failed. (%d)"), wrapperGetLastError()); } } return; } /* New connection, so continue. */ protocolActiveBackendSD = newBackendSD; if (wrapperData->isDebugging) { if (IPv4) { port = ntohs(addr_srv4.sin_port); } else { port = ntohs(addr_srv6.sin6_port); } log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_INFO, TEXT("accepted a socket from %s on port %d"), socketSource, port); } free(socketSource); /* Make the socket non-blocking */ #ifdef WIN32 rc = ioctlsocket(protocolActiveBackendSD, FIONBIO, &dwNoBlock); #else /* UNIX */ rc = fcntl(protocolActiveBackendSD, F_SETFL, O_NONBLOCK); #endif if (rc == SOCKET_ERROR) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("socket ioctlsocket failed. (%s)"), getLastErrorText()); } wrapperProtocolClose(); return; } /* We got an incoming connection, so close down the listener to prevent further connections. */ protocolStopServer(); } /** * Attempt to accept a connection from a JVM client. */ void protocolOpen() { if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) { protocolOpenPipe(); } else if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_SOCKET_V6) { protocolOpenSocket(FALSE); } else { protocolOpenSocket(TRUE); } } void protocolClosePipe() { #ifndef WIN32 size_t pipeNameLen; TCHAR *pipeName; pipeNameLen = 12 + 10 + 1 + 10 + 3; #endif if (protocolActiveServerPipeConnected) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("Closing backend pipe.")); } #ifdef WIN32 if (protocolActiveServerPipeIn != INVALID_HANDLE_VALUE && !CloseHandle(protocolActiveServerPipeIn)) { #else if (close(protocolActiveServerPipeIn) == -1) { #endif log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("Failed to close backend pipe: %s"), getLastErrorText()); } #ifdef WIN32 if (protocolActiveServerPipeOut != INVALID_HANDLE_VALUE && !CloseHandle(protocolActiveServerPipeOut)) { #else if (close(protocolActiveServerPipeOut) == -1) { #endif log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("Failed to close backend pipe: %s"), getLastErrorText()); } #ifndef WIN32 pipeName = malloc(sizeof(TCHAR) * (pipeNameLen + 1)); if (!pipeName) { outOfMemory(TEXT("PCP"), 1); return; } _sntprintf(pipeName, pipeNameLen, TEXT("/tmp/wrapper-%d-%d-in"), wrapperData->wrapperPID, wrapperData->jvmRestarts); _tunlink(pipeName); _sntprintf(pipeName, pipeNameLen, TEXT("/tmp/wrapper-%d-%d-out"), wrapperData->wrapperPID, wrapperData->jvmRestarts); _tunlink(pipeName); #endif protocolActiveServerPipeConnected = FALSE; protocolActiveServerPipeStarted = FALSE; protocolActiveServerPipeIn = INVALID_HANDLE_VALUE; protocolActiveServerPipeOut = INVALID_HANDLE_VALUE; } } void protocolCloseSocket() { int rc; /* Close the socket. */ if (protocolActiveBackendSD != INVALID_SOCKET) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("Closing backend socket.")); } #ifdef WIN32 rc = closesocket(protocolActiveBackendSD); #else /* UNIX */ rc = close(protocolActiveBackendSD); #endif if (rc == SOCKET_ERROR) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("socket close failed. (%d)"), wrapperGetLastError()); } } protocolActiveBackendSD = INVALID_SOCKET; } } /** * Close the backend socket. */ void wrapperProtocolClose() { if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) { protocolClosePipe(); } else { protocolCloseSocket(); } } /** * Returns the name of a given function code for debug purposes. */ TCHAR *wrapperProtocolGetCodeName(char code) { static TCHAR unknownBuffer[14]; TCHAR *name; switch (code) { case WRAPPER_MSG_START: name = TEXT("START"); break; case WRAPPER_MSG_STOP: name = TEXT("STOP"); break; case WRAPPER_MSG_RESTART: name = TEXT("RESTART"); break; case WRAPPER_MSG_PING: name = TEXT("PING"); break; case WRAPPER_MSG_STOP_PENDING: name = TEXT("STOP_PENDING"); break; case WRAPPER_MSG_START_PENDING: name = TEXT("START_PENDING"); break; case WRAPPER_MSG_STARTED: name = TEXT("STARTED"); break; case WRAPPER_MSG_STOPPED: name = TEXT("STOPPED"); break; case WRAPPER_MSG_KEY: name = TEXT("KEY"); break; case WRAPPER_MSG_BADKEY: name = TEXT("BADKEY"); break; case WRAPPER_MSG_LOW_LOG_LEVEL: name = TEXT("LOW_LOG_LEVEL"); break; case WRAPPER_MSG_PING_TIMEOUT: /* No longer used. */ name = TEXT("PING_TIMEOUT"); break; case WRAPPER_MSG_SERVICE_CONTROL_CODE: name = TEXT("SERVICE_CONTROL_CODE"); break; case WRAPPER_MSG_PROPERTIES: name = TEXT("PROPERTIES"); break; case WRAPPER_MSG_LOG + LEVEL_DEBUG: name = TEXT("LOG(DEBUG)"); break; case WRAPPER_MSG_LOG + LEVEL_INFO: name = TEXT("LOG(INFO)"); break; case WRAPPER_MSG_LOG + LEVEL_STATUS: name = TEXT("LOG(STATUS)"); break; case WRAPPER_MSG_LOG + LEVEL_WARN: name = TEXT("LOG(WARN)"); break; case WRAPPER_MSG_LOG + LEVEL_ERROR: name = TEXT("LOG(ERROR)"); break; case WRAPPER_MSG_LOG + LEVEL_FATAL: name = TEXT("LOG(FATAL)"); break; case WRAPPER_MSG_LOG + LEVEL_ADVICE: name = TEXT("LOG(ADVICE)"); break; case WRAPPER_MSG_LOG + LEVEL_NOTICE: name = TEXT("LOG(NOTICE)"); break; case WRAPPER_MSG_LOGFILE: name = TEXT("LOGFILE"); break; case WRAPPER_MSG_APPEAR_ORPHAN: /* No longer used. */ name = TEXT("APPEAR_ORPHAN"); break; case WRAPPER_MSG_PAUSE: name = TEXT("PAUSE"); break; case WRAPPER_MSG_RESUME: name = TEXT("RESUME"); break; case WRAPPER_MSG_GC: name = TEXT("GC"); break; default: _sntprintf(unknownBuffer, 14, TEXT("UNKNOWN(%d)"), code); name = unknownBuffer; break; } return name; } /* Mutex for syncronization of the wrapperProtocolFunction function. */ #ifdef WIN32 HANDLE protocolMutexHandle = NULL; #else pthread_mutex_t protocolMutex = PTHREAD_MUTEX_INITIALIZER; #endif /** Obtains a lock on the protocol mutex. */ int lockProtocolMutex() { #ifdef WIN32 switch (WaitForSingleObject(protocolMutexHandle, INFINITE)) { case WAIT_ABANDONED: _tprintf(TEXT("Protocol mutex was abandoned.\n")); fflush(NULL); return -1; case WAIT_FAILED: _tprintf(TEXT("Protocol mutex wait failed.\n")); fflush(NULL); return -1; case WAIT_TIMEOUT: _tprintf(TEXT("Protocol mutex wait timed out.\n")); fflush(NULL); return -1; default: /* Ok */ break; } #else if (pthread_mutex_lock(&protocolMutex)) { _tprintf(TEXT("Failed to lock the Protocol mutex. %s\n"), getLastErrorText()); return -1; } #endif return 0; } /** Releases a lock on the protocol mutex. */ int releaseProtocolMutex() { #ifdef WIN32 if (!ReleaseMutex(protocolMutexHandle)) { _tprintf(TEXT("Failed to release Protocol mutex. %s\n"), getLastErrorText()); fflush(NULL); return -1; } #else if (pthread_mutex_unlock(&protocolMutex)) { _tprintf(TEXT("Failed to unlock the Protocol mutex. %s\n"), getLastErrorText()); return -1; } #endif return 0; } size_t protocolSendBufferSize = 0; char *protocolSendBuffer = NULL; /** * Sends a command to the JVM process. * * @param function The command to send. (This is intentionally an 8-bit char.) * @param message Message to send along with the command. * * @return TRUE if there were any problems. */ int wrapperProtocolFunction(char function, const TCHAR *messageW) { #ifdef UNICODE #ifdef WIN32 TCHAR buffer[16]; UINT cp; #endif #endif int rc; int cnt; int sendCnt; int inWritten; size_t len; TCHAR *logMsgW; const TCHAR *messageTemplate; char *messageMB = NULL; int returnVal = FALSE; int ok = TRUE; size_t sent; #ifdef WIN32 int maxSendSize; #endif /* It is important than there is never more than one thread allowed in here at a time. */ if (lockProtocolMutex()) { return TRUE; } if (ok) { /* We will be trasmitting a MultiByte string of characters. So we need to convert the messageW. */ if (messageW) { #ifdef UNICODE #ifdef WIN32 GetLocaleInfo(GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE, buffer, sizeof(buffer)); cp = _ttoi(buffer); len = WideCharToMultiByte(CP_OEMCP, 0, messageW, -1, NULL, 0, NULL, NULL); if (len <= 0) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_WARN, TEXT("Invalid multibyte sequence in %s \"%s\" : %s"), TEXT("protocol message"), messageW, getLastErrorText()); returnVal = TRUE; ok = FALSE; } else { messageMB = malloc(len); if (!messageMB) { outOfMemory(TEXT("WPF"), 2); returnVal = TRUE; ok = FALSE; } else { WideCharToMultiByte(CP_OEMCP, 0, messageW, -1, messageMB, (int)len, NULL, NULL); } } #else len = wcstombs(NULL, messageW, 0); if (len == (size_t)-1) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_WARN, TEXT("Invalid multibyte sequence in %s \"%s\" : %s"), TEXT("protocol message"), messageW, getLastErrorText()); returnVal = TRUE; ok = FALSE; } else { messageMB = malloc(len + 1); if (!messageMB) { outOfMemory(TEXT("WPF"), 3); returnVal = TRUE; ok = FALSE; } else { wcstombs(messageMB, messageW, len + 1); } } #endif #else len = _tscslen(messageW) + 1; messageMB = malloc(len); if (!messageMB) { outOfMemory(TEXT("WPF"), 4); returnVal = TRUE; ok = FALSE; } else { _tcsncpy(messageMB, messageW, len); } #endif } else { messageMB = NULL; } } /* We don't want to show the full properties log message. It is quite long and distracting. */ if (function == WRAPPER_MSG_PROPERTIES) { messageTemplate = TEXT("(Property Values, Size=%d)"); len = _tcslen(messageTemplate) + 16 + 1; logMsgW = malloc(sizeof(TCHAR) * len); if (!logMsgW) { outOfMemory(TEXT("WPF"), 1); /* Fallback to raw message. Not ideal but Ok. */ logMsgW = (TCHAR*)messageW; /* Strip the const, but will never be modified. */ } else { /* messageMB should never be NULL, but for code checker be careful. */ _sntprintf(logMsgW, len, messageTemplate, (messageMB ? strlen(messageMB) : 0)); } } else { logMsgW = (TCHAR*)messageW; /* Strip the const, but will never be modified. */ } if (ok) { /* We need to construct a single string that will be used to transmit the command + message. */ if (messageMB) { len = 1 + strlen(messageMB) + 1; } else { len = 2; } if (protocolSendBufferSize < len) { if (protocolSendBuffer) { free(protocolSendBuffer); } protocolSendBuffer = malloc(sizeof(char) * len); if (!protocolSendBuffer) { outOfMemory(TEXT("WPF"), 4); returnVal = TRUE; ok = FALSE; } else { /* Build the packet */ protocolSendBuffer[0] = function; if (messageMB) { strncpy(&(protocolSendBuffer[1]), messageMB, len - 1); } else { protocolSendBuffer[1] = 0; } } } if (messageMB) { free(messageMB); } } if (ok) { if (((protocolActiveBackendSD == INVALID_SOCKET) && (wrapperData->backendType == WRAPPER_BACKEND_TYPE_SOCKET)) || ((protocolActiveServerPipeConnected == FALSE) && (wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE))) { /* A socket was not opened */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("Socket not open, so packet not sent %s : %s"), wrapperProtocolGetCodeName(function), (logMsgW == NULL ? TEXT("NULL") : logMsgW)); } returnVal = TRUE; } else { if (wrapperData->isDebugging) { if ((function == WRAPPER_MSG_PING) && messageW && (_tcsstr(messageW, TEXT("silent")) == messageW)) { /* log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("Send a silent ping packet %s : %s"), wrapperProtocolGetCodeName(function), (logMsgW == NULL ? TEXT("NULL") : logMsgW)); */ } else { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("Send a packet %s : %s"), wrapperProtocolGetCodeName(function), (logMsgW == NULL ? TEXT("NULL") : logMsgW)); } } /* When actually sending the packet, we need to be careful to make sure that the entire packet gets sent. * There isssues on both sockets and Pipes where the send will fail if the packet is too large. * In such cases, it needs to be broken up into multiple calls. * This is currently only an issue with the PROPERTIES packet. */ if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) { sent = 0; cnt = 0; sendCnt = 0; #ifdef WIN32 maxSendSize = 40000; #endif while ((sent < len) && (cnt < 200)) { if (cnt > 0) { wrapperSleep(10); } #ifdef WIN32 /* Send a maximum of 32000 characters per call as larger values appear to fail without error. */ if (WriteFile(protocolActiveServerPipeOut, protocolSendBuffer + sent, __min(maxSendSize, sizeof(char) * (int)(len - sent)), &inWritten, NULL) == FALSE) { #else if ((inWritten = write(protocolActiveServerPipeOut, protocolSendBuffer + sent, sizeof(char) * (int)(len - sent))) == -1) { #endif log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_FATAL, TEXT("Writing to the backend pipe failed (%d): %s"), wrapperGetLastError(), getLastErrorText()); returnVal = TRUE; break; #ifdef WIN32 } else if (inWritten == 0) { /* Didn't write anything, but not an error. * Have not found this documented anywhere, but it happens if the size is larger than some hidden limit. */ maxSendSize = __max(512, (int)(maxSendSize * 0.90)); sendCnt++; #endif } else { /* Write N characters */ if (((sent + inWritten < len) || (sendCnt > 0)) && wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT(" Sent %d bytes, %d remaining."), inWritten, len - sent - inWritten ); } sent += inWritten; sendCnt++; } cnt++; } if (sent < len) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("%s send failed. Incomplete. Sent %d of %d bytes."), TEXT("Pipe"), sent, len); returnVal = TRUE; } } else { sent = 0; cnt = 0; sendCnt = 0; rc = 0; while ((sent < len) && (cnt < 200)) { if (cnt > 0) { wrapperSleep(10); } rc = send(protocolActiveBackendSD, protocolSendBuffer + sent, sizeof(char) * (int)(len - sent), 0); if (rc == SOCKET_ERROR) { if (wrapperGetLastError() == WRAPPER_EWOULDBLOCK) { /* The output buffer is simply full right now. Try again in a bit. */ } else { break; } } else if (rc < 0) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("Send unexpectedly returned %d"), rc); break; } else { /* Wrote N characters. */ if (((sent + rc < len) || (sendCnt > 0)) && wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT(" Sent %d bytes, %d remaining."), rc, len - sent - rc ); } sent += rc; sendCnt++; } cnt++; } if (rc == SOCKET_ERROR) { if (wrapperGetLastError() == WRAPPER_EWOULDBLOCK) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_WARN, TEXT("Socket send failed. Blocked for 2 seconds. %s"), getLastErrorText()); #ifdef WIN32 } else if (wrapperGetLastError() == WSAECONNRESET) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("Socket send failed. %s"), getLastErrorText()); #endif } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("Socket send failed. %s"), getLastErrorText()); } } wrapperProtocolClose(); returnVal = TRUE; } else if (sent < len) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_ERROR, TEXT("%s send failed. Incomplete. Sent %d of %d bytes."), TEXT("Socket"), sent, len); returnVal = TRUE; } else { returnVal = FALSE; } } } } /* Free up the logMsgW if we allocated it. */ if (logMsgW != messageW) { free(logMsgW); } /* Always make sure the mutex is released. */ if (releaseProtocolMutex()) { returnVal = TRUE; } return returnVal; } /** * Checks the status of the server backend. * * The backend will be initialized if the JVM is in a state where it should * be up, otherwise the backend will be left alone. * * If the forceOpen flag is set then an attempt will be made to initialize * the backend regardless of the JVM state. * * Returns TRUE if the backend is open and ready on return, FALSE if not. */ int wrapperCheckServerBackend(int forceOpen) { if (((wrapperData->backendType & WRAPPER_BACKEND_TYPE_SOCKET) && (protocolActiveServerSD == INVALID_SOCKET)) || ((wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) && (protocolActiveServerPipeStarted == FALSE)) ) { /* The backend is not currently open and needs to be started, * unless the JVM is DOWN or in a state where it is not needed. */ if ((!forceOpen) && ((wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) || (wrapperData->jState == WRAPPER_JSTATE_LAUNCH_DELAY) || (wrapperData->jState == WRAPPER_JSTATE_RESTART) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED) || (wrapperData->jState == WRAPPER_JSTATE_KILLING) || (wrapperData->jState == WRAPPER_JSTATE_KILL) || (wrapperData->jState == WRAPPER_JSTATE_KILLED) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH))) { /* The JVM is down or in a state where the backend is not needed. */ return FALSE; } else { /* The backend should be open, try doing so. */ protocolStartServer(); if ( ((wrapperData->backendType & WRAPPER_BACKEND_TYPE_SOCKET) && (protocolActiveServerSD == INVALID_SOCKET)) || ((wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) && (protocolActiveServerPipeStarted == FALSE)) ) { /* Failed. */ return FALSE; } else { return TRUE; } } } else { /* Backend is ready. */ return TRUE; } } /** * Simple function to parse hexidecimal numbers into a TICKS */ TICKS hexToTICKS(TCHAR *buffer) { TICKS value = 0; TCHAR c; int pos = 0; while (TRUE) { c = buffer[pos]; if ((c >= TEXT('a')) && (c <= TEXT('f'))) { value = (value << 4) + (10 + c - TEXT('a')); } else if ((c >= TEXT('A')) && (c <= TEXT('F'))) { value = (value << 4) + (10 + c - TEXT('A')); } else if ((c >= TEXT('0')) && (c <= TEXT('9'))) { value = (value << 4) + (c - TEXT('0')); } else { /* Any other character or null is the end of the number. */ return value; } pos++; } } /** * Read any data sent from the JVM. This function will loop and read as many * packets are available. The loop will only be allowed to go for 250ms to * ensure that other functions are handled correctly. * * Returns 0 if all available data has been read, 1 if more data is waiting. */ int wrapperProtocolRead() { char c; char code; int len; #ifdef WIN32 int maxlen; #endif int pos; TCHAR *tc; int err; struct timeb timeBuffer; time_t startTime; int startTimeMillis; time_t now; int nowMillis; time_t durr; #ifdef WIN32 TCHAR cpBuffer[16]; UINT cp; #endif size_t req; wrapperGetCurrentTime(&timeBuffer); startTime = now = timeBuffer.time; startTimeMillis = nowMillis = timeBuffer.millitm; /* log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("now=%ld, nowMillis=%d"), now, nowMillis); */ while((durr = (now - startTime) * 1000 + (nowMillis - startTimeMillis)) < 250) { /* log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("durr=%ld"), durr); */ /* If we have an open client backend, then use it. */ if (((wrapperData->backendType & WRAPPER_BACKEND_TYPE_SOCKET) && (protocolActiveBackendSD == INVALID_SOCKET)) || ((wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) && (protocolActiveServerPipeConnected == FALSE))) { /* A Client backend is not open */ /* Is the server backend open? */ if (!wrapperCheckServerBackend(FALSE)) { /* Backend is down. We can not read any packets. */ return 0; } /* Try accepting a connection */ protocolOpen(); if (((wrapperData->backendType & WRAPPER_BACKEND_TYPE_SOCKET) && (protocolActiveBackendSD == INVALID_SOCKET)) || ((wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) && (protocolActiveServerPipeConnected == FALSE))) { return 0; } } if (wrapperData->backendType & WRAPPER_BACKEND_TYPE_SOCKET) { /* Try receiving a packet code */ len = recv(protocolActiveBackendSD, (void*) &c, 1, 0); if (len == SOCKET_ERROR) { err = wrapperGetLastError(); if ((err != WRAPPER_EWOULDBLOCK) && /* Windows - Would block. */ (err != EAGAIN)) { /* UNIX - Would block. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("socket read failed. (%s)"), getLastErrorText()); } wrapperProtocolClose(); } return 0; } else if (len != 1) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("socket read no code (closed?).")); } wrapperProtocolClose(); return 0; } code = (char)c; /* Read in any message */ pos = 0; do { len = recv(protocolActiveBackendSD, (void*) &c, 1, 0); if (len == 1) { if (c == 0) { /* End of string */ len = 0; } else if (pos < MAX_LOG_SIZE) { packetBufferMB[pos] = c; pos++; } } else { len = 0; } } while (len == 1); /* terminate the string; */ packetBufferMB[pos] = '\0'; } else if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) { #ifdef WIN32 err = PeekNamedPipe(protocolActiveServerPipeIn, NULL, 0, NULL, &maxlen, NULL); if ((err == 0) && (GetLastError() == ERROR_BROKEN_PIPE)) { /* ERROR_BROKEN_PIPE - the client has closed the pipe. So most likely it just exited */ protocolActiveServerPipeIn = INVALID_HANDLE_VALUE; } if (maxlen == 0) { /*no data available */ return 0; } if (ReadFile(protocolActiveServerPipeIn, &c, 1, &len, NULL) == TRUE || GetLastError() == ERROR_MORE_DATA) { code = (char)c; --maxlen; pos = 0; do { ReadFile(protocolActiveServerPipeIn, &c, 1, &len, NULL); if (len == 1) { if (c == 0) { /* End of string */ len = 0; } else if (pos < MAX_LOG_SIZE) { packetBufferMB[pos] = c; pos++; } } else { len = 0; } } while (len == 1 && maxlen-- >= 0); packetBufferMB[pos] = '\0'; } else { if (GetLastError() == ERROR_INVALID_HANDLE) { return 0; } else { wrapperProtocolClose(); return 0; } } #else len = read(protocolActiveServerPipeIn, (void*) &c, 1); if (len == SOCKET_ERROR) { err = wrapperGetLastError(); if ((err != WRAPPER_EWOULDBLOCK) && /* Windows - Would block. */ (err != EAGAIN)) { /* UNIX - Would block. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("pipe read failed. (%s)"), getLastErrorText()); } wrapperProtocolClose(); } return 0; } else if (len == 0) { /*nothing read...*/ return 0; } code = (char)c; /* Read in any message */ pos = 0; do { len = read(protocolActiveServerPipeIn, (void*) &c, 1); if (len == 1) { if (c == 0) { /* End of string */ len = 0; } else if (pos < MAX_LOG_SIZE) { packetBufferMB[pos] = c; pos++; } } else { len = 0; } } while (len == 1); /* terminate the string; */ packetBufferMB[pos] = '\0'; #endif } else { /* Should not reach this part because wrapperData->backendType should always have a valid value */ return 0; } /* Convert the multi-byte packetBufferMB buffer into a wide-character string. */ /* Source message is always smaller than the MAX_LOG_SIZE so the output will be as well. */ #ifdef WIN32 GetLocaleInfo(GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE, cpBuffer, sizeof(cpBuffer)); cp = _ttoi(cpBuffer); req = MultiByteToWideChar(cp, 0, packetBufferMB, -1, packetBufferW, MAX_LOG_SIZE + 1); if (req <= 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Invalid multibyte sequence in %s: %s"), TEXT("protocol message"), getLastErrorText()); packetBufferW[0] = TEXT('\0'); } #else req = mbstowcs(packetBufferW, packetBufferMB, MAX_LOG_SIZE + 1); if (req == (size_t)-1) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_WARN, TEXT("Invalid multibyte sequence in %s: %s"), TEXT("protocol message"), getLastErrorText()); packetBufferW[0] = TEXT('\0'); } #endif if (wrapperData->isDebugging) { if ((code == WRAPPER_MSG_PING) && (_tcsstr(packetBufferW, TEXT("silent")) == packetBufferW)) { /* log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("read a silent ping packet %s : %s"), wrapperProtocolGetCodeName(code), packetBufferW); */ } else { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("read a packet %s : %s"), wrapperProtocolGetCodeName(code), packetBufferW); } } switch (code) { case WRAPPER_MSG_STOP: wrapperStopRequested(_ttoi(packetBufferW)); break; case WRAPPER_MSG_RESTART: wrapperRestartRequested(); break; case WRAPPER_MSG_PING: /* Because all versions of the wrapper.jar simply bounce back the ping message, the pingSendTicks should always exist. */ tc = _tcschr(packetBufferW, TEXT(' ')); if (tc) { /* A pingSendTicks should exist. Parse the id following the space. It will be in the format 0xffffffff. */ wrapperPingResponded(hexToTICKS(&tc[1]), TRUE); } else { /* Should not happen, but just in case use the current ticks. */ wrapperPingResponded(wrapperGetTicks(), FALSE); } break; case WRAPPER_MSG_STOP_PENDING: wrapperStopPendingSignaled(_ttoi(packetBufferW)); break; case WRAPPER_MSG_STOPPED: wrapperStoppedSignaled(); break; case WRAPPER_MSG_START_PENDING: wrapperStartPendingSignaled(_ttoi(packetBufferW)); break; case WRAPPER_MSG_STARTED: wrapperStartedSignaled(); break; case WRAPPER_MSG_KEY: wrapperKeyRegistered(packetBufferW); break; case WRAPPER_MSG_LOG + LEVEL_DEBUG: case WRAPPER_MSG_LOG + LEVEL_INFO: case WRAPPER_MSG_LOG + LEVEL_STATUS: case WRAPPER_MSG_LOG + LEVEL_WARN: case WRAPPER_MSG_LOG + LEVEL_ERROR: case WRAPPER_MSG_LOG + LEVEL_FATAL: wrapperLogSignaled(code - WRAPPER_MSG_LOG, packetBufferW); break; case WRAPPER_MSG_APPEAR_ORPHAN: /* No longer used. This is still here in case a mix of versions are used. */ break; default: if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_PROTOCOL, LEVEL_DEBUG, TEXT("received unknown packet (%d:%s)"), code, packetBufferW); } break; } /* Get the time again */ wrapperGetCurrentTime(&timeBuffer); now = timeBuffer.time; nowMillis = timeBuffer.millitm; } /* log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("done durr=%ld"), durr); */ if ((durr = (now - startTime) * 1000 + (nowMillis - startTimeMillis)) < 250) { return 0; } else { return 1; } } /****************************************************************************** * Wrapper inner methods. *****************************************************************************/ /** * IMPORTANT - Any logging done in here needs to be queued or it would cause a recursion problem. * * It is also critical that this is NEVER called from within the protocol function because it * would cause a deadlock with the protocol semaphore. This means that it can never be called * from within log_printf(...). */ void wrapperLogFileChanged(const TCHAR *logFile) { if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("active log file changed: %s"), logFile); } /* On startup, this function will always be called the first time the log file is set, * we don't want to send the command in this case as it clutters the debug log output. * Besides, the JVM will not be running anyway. */ if (wrapperData->jState != WRAPPER_JSTATE_DOWN_CLEAN) { wrapperProtocolFunction(WRAPPER_MSG_LOGFILE, logFile); } } /** * Pre initialize the wrapper. */ int wrapperInitialize() { TCHAR *retLocale; #ifdef WIN32 int maxPathLen = _MAX_PATH; #else int maxPathLen = PATH_MAX; #endif /* Initialize the properties variable. */ properties = NULL; /* Initialize the random seed. */ srand((unsigned)time(NULL)); /* Make sure all values are reliably set to 0. All required values should also be * set below, but this extra step will protect against future changes. Some * platforms appear to initialize maloc'd memory to 0 while others do not. */ wrapperData = malloc(sizeof(WrapperConfig)); if (!wrapperData) { outOfMemory(TEXT("WI"), 1); return 1; } memset(wrapperData, 0, sizeof(WrapperConfig)); /* Setup the initial values of required properties. */ wrapperData->configured = FALSE; wrapperData->isConsole = TRUE; wrapperSetWrapperState(WRAPPER_WSTATE_STARTING); wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, 0, -1); wrapperData->lastPingTicks = wrapperGetTicks(); wrapperData->lastLoggedPingTicks = wrapperGetTicks(); wrapperData->jvmVersionCommand = NULL; wrapperData->jvmCommand = NULL; wrapperData->exitRequested = FALSE; wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_INITIAL; /* The first JVM needs to be started. */ wrapperData->exitCode = 0; wrapperData->jvmRestarts = 0; wrapperData->jvmLaunchTicks = wrapperGetTicks(); wrapperData->failedInvocationCount = 0; wrapperData->originalWorkingDir = NULL; wrapperData->configFile = NULL; wrapperData->workingDir = NULL; wrapperData->outputFilterCount = 0; wrapperData->confDir = NULL; wrapperData->umask = -1; wrapperData->language = NULL; wrapperData->portAddress = NULL; wrapperData->pingTimedOut = FALSE; #ifdef WIN32 if (!(tickMutexHandle = CreateMutex(NULL, FALSE, NULL))) { printf("Failed to create tick mutex. %s\n", getLastErrorText()); return 1; } /* Initialize control code queue. */ wrapperData->ctrlCodeQueue = malloc(sizeof(int) * CTRL_CODE_QUEUE_SIZE); if (!wrapperData->ctrlCodeQueue) { outOfMemory(TEXT("WI"), 2); return 1; } wrapperData->ctrlCodeQueueWriteIndex = 0; wrapperData->ctrlCodeQueueReadIndex = 0; wrapperData->ctrlCodeQueueWrapped = FALSE; #endif if (initLogging(wrapperLogFileChanged)) { return 1; } /* This will only be called by the main thread on startup. * Immediately register this thread with the logger. * This has to happen after the logging is initialized. */ logRegisterThread(WRAPPER_THREAD_MAIN); setLogfilePath(TEXT("wrapper.log"), NULL, FALSE); setLogfileRollMode(ROLL_MODE_SIZE); setLogfileFormat(TEXT("LPTM")); setLogfileLevelInt(LEVEL_DEBUG); setLogfileAutoClose(FALSE); setConsoleLogFormat(TEXT("LPM")); setConsoleLogLevelInt(LEVEL_DEBUG); setConsoleFlush(TRUE); /* Always flush immediately until the logfile is configured to make sure that problems are in a consistent location. */ setSyslogLevelInt(LEVEL_NONE); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper Initializing... Minimum logging configured.")); #endif /** Remember what the initial user directory was when the Wrapper was launched. */ wrapperData->initialPath = (TCHAR *)malloc((maxPathLen + 1) * sizeof(TCHAR)); if (!wrapperData->initialPath) { outOfMemory(TEXT("WI"), 3); return 1; } else { if (!(wrapperData->initialPath = _tgetcwd((TCHAR*)wrapperData->initialPath, maxPathLen + 1))) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Failed to get the initial directory. (%s)"), getLastErrorText()); return 1; } } /* Set a variable to the initial working directory. */ setEnv(TEXT("WRAPPER_INIT_DIR"), wrapperData->initialPath, ENV_SOURCE_APPLICATION); #ifdef WIN32 if (!(protocolMutexHandle = CreateMutex(NULL, FALSE, NULL))) { _tprintf(TEXT("Failed to create protocol mutex. %s\n"), getLastErrorText()); fflush(NULL); return 1; } #endif /* This is a sanity check to make sure that the datatype used for tick counts is correct. */ if (sizeof(TICKS) != 4) { printf("Tick size incorrect %d != 4\n", (int)sizeof(TICKS)); fflush(NULL); return 1; } /* Set the default locale here so any startup error messages will have a chance of working. * We will go back and try to set the actual locale again later once it is configured. */ retLocale = _tsetlocale(LC_ALL, TEXT("")); if (retLocale) { /* Success. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("tsetlocale() returned \"%s\""), retLocale); #endif #if !defined(WIN32) && defined(UNICODE) free(retLocale); #endif } else { /* Failure. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("tsetlocale() returned NULL")); #endif } if (loadEnvironment()) { return 1; } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper Initialization complete.")); #endif return 0; } void wrapperDataDispose() { int i; if (wrapperData->workingDir) { free(wrapperData->workingDir); wrapperData->workingDir = NULL; } if (wrapperData->originalWorkingDir) { free(wrapperData->originalWorkingDir); wrapperData->originalWorkingDir = NULL; } if (wrapperData->configFile) { free(wrapperData->configFile); wrapperData->configFile = NULL; } if (wrapperData->initialPath) { free(wrapperData->initialPath); wrapperData->initialPath = NULL; } if (wrapperData->classpath) { free(wrapperData->classpath); wrapperData->classpath = NULL; } if (wrapperData->portAddress) { free(wrapperData->portAddress); wrapperData->portAddress = NULL; } #ifdef WIN32 if (wrapperData->jvmVersionCommand) { free(wrapperData->jvmVersionCommand); wrapperData->jvmVersionCommand = NULL; } if (wrapperData->jvmCommand) { free(wrapperData->jvmCommand); wrapperData->jvmCommand = NULL; } if (wrapperData->userName) { free(wrapperData->userName); wrapperData->userName = NULL; } if (wrapperData->domainName) { free(wrapperData->domainName); wrapperData->domainName = NULL; } if (wrapperData->ntServiceLoadOrderGroup) { free(wrapperData->ntServiceLoadOrderGroup); wrapperData->ntServiceLoadOrderGroup = NULL; } if (wrapperData->ntServiceDependencies) { free(wrapperData->ntServiceDependencies); wrapperData->ntServiceDependencies = NULL; } if (wrapperData->ntServiceAccount) { free(wrapperData->ntServiceAccount); wrapperData->ntServiceAccount = NULL; } if (wrapperData->ntServicePassword) { free(wrapperData->ntServicePassword); wrapperData->ntServicePassword = NULL; } if (wrapperData->ctrlCodeQueue) { free(wrapperData->ctrlCodeQueue); wrapperData->ctrlCodeQueue = NULL; } #else if(wrapperData->jvmVersionCommand) { for (i = 0; wrapperData->jvmVersionCommand[i] != NULL; i++) { free(wrapperData->jvmVersionCommand[i]); wrapperData->jvmVersionCommand[i] = NULL; } free(wrapperData->jvmVersionCommand); wrapperData->jvmVersionCommand = NULL; } if(wrapperData->jvmCommand) { for (i = 0; wrapperData->jvmCommand[i] != NULL; i++) { free(wrapperData->jvmCommand[i]); wrapperData->jvmCommand[i] = NULL; } free(wrapperData->jvmCommand); wrapperData->jvmCommand = NULL; } #endif if (wrapperData->outputFilterCount > 0) { for (i = 0; i < wrapperData->outputFilterCount; i++) { if (wrapperData->outputFilters[i]) { free(wrapperData->outputFilters[i]); wrapperData->outputFilters[i] = NULL; } if (wrapperData->outputFilterActionLists[i]) { free(wrapperData->outputFilterActionLists[i]); wrapperData->outputFilterActionLists[i] = NULL; } } if (wrapperData->outputFilters) { free(wrapperData->outputFilters); wrapperData->outputFilters = NULL; } if (wrapperData->outputFilterActionLists) { free(wrapperData->outputFilterActionLists); wrapperData->outputFilterActionLists = NULL; } if (wrapperData->outputFilterMessages) { free(wrapperData->outputFilterMessages); wrapperData->outputFilterMessages = NULL; } if (wrapperData->outputFilterAllowWildFlags) { free(wrapperData->outputFilterAllowWildFlags); wrapperData->outputFilterAllowWildFlags = NULL; } if (wrapperData->outputFilterMinLens) { free(wrapperData->outputFilterMinLens); wrapperData->outputFilterMinLens = NULL; } } if (wrapperData->pidFilename) { free(wrapperData->pidFilename); wrapperData->pidFilename = NULL; } if (wrapperData->lockFilename) { free(wrapperData->lockFilename); wrapperData->lockFilename = NULL; } if (wrapperData->javaPidFilename) { free(wrapperData->javaPidFilename); wrapperData->javaPidFilename = NULL; } if (wrapperData->javaIdFilename) { free(wrapperData->javaIdFilename); wrapperData->javaIdFilename = NULL; } if (wrapperData->statusFilename) { free(wrapperData->statusFilename); wrapperData->statusFilename = NULL; } if (wrapperData->javaStatusFilename) { free(wrapperData->javaStatusFilename); wrapperData->javaStatusFilename = NULL; } if (wrapperData->commandFilename) { free(wrapperData->commandFilename); wrapperData->commandFilename = NULL; } if (wrapperData->consoleTitle) { free(wrapperData->consoleTitle); wrapperData->consoleTitle = NULL; } if (wrapperData->serviceName) { free(wrapperData->serviceName); wrapperData->serviceName = NULL; } if (wrapperData->serviceDisplayName) { free(wrapperData->serviceDisplayName); wrapperData->serviceDisplayName = NULL; } if (wrapperData->serviceDescription) { free(wrapperData->serviceDescription); wrapperData->serviceDescription = NULL; } if (wrapperData->hostName) { free(wrapperData->hostName); wrapperData->hostName = NULL; } if (wrapperData->confDir) { free(wrapperData->confDir); wrapperData->confDir = NULL; } if (wrapperData->argConfFileDefault && wrapperData->argConfFile) { free(wrapperData->argConfFile); wrapperData->argConfFile = NULL; } if (wrapperData) { free(wrapperData); wrapperData = NULL; } } /** Common wrapper cleanup code. */ void wrapperDispose() { /* Make sure not to dispose twice. This should not happen, but check for safety. */ if (disposed) { /* Don't use log_printf here as the second call may have already disposed logging. */ _tprintf(TEXT("wrapperDispose was called more than once.\n")); return; } disposed = TRUE; #ifdef WIN32 if (protocolMutexHandle) { if (!CloseHandle(protocolMutexHandle)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to close protocol mutex handle. %s"), getLastErrorText()); } } /* Make sure that the startup thread has completed. */ disposeStartup(); #endif /* Clean up the javaIO thread. This should be done before the timer thread. */ if (wrapperData->useJavaIOThread) { disposeJavaIO(); } /* Clean up the timer thread. */ if (!wrapperData->useSystemTime) { disposeTimer(); } /* Clean up the properties structure. */ disposeProperties(properties); properties = NULL; disposeEnvironment(); if (wrapperChildWorkBuffer) { free(wrapperChildWorkBuffer); wrapperChildWorkBuffer = NULL; } if (protocolSendBuffer) { free(protocolSendBuffer); protocolSendBuffer = NULL; } /* Clean up the logging system. Should happen near last. */ disposeLogging(); /* clean up the main wrapper data structure. This must be done last.*/ wrapperDataDispose(); } /** * Returns the file name base as a newly malloced TCHAR *. The resulting * base file name will have any path and extension stripped. * * baseName should be long enough to always contain the base name. * (_tcslen(fileName) + 1) is safe. */ void wrapperGetFileBase(const TCHAR *fileName, TCHAR *baseName) { const TCHAR *start; const TCHAR *end; const TCHAR *c; start = fileName; end = &fileName[_tcslen(fileName)]; /* Strip off any path. */ #ifdef WIN32 c = _tcsrchr(start, TEXT('\\')); #else c = _tcsrchr(start, TEXT('/')); #endif if (c) { start = &c[1]; } /* Strip off any extension. */ c = _tcsrchr(start, TEXT('.')); if (c) { end = c; } /* Now create the new base name. */ _tcsncpy(baseName, start, end - start); baseName[end - start] = TEXT('\0'); } /** * Returns a buffer containing a multi-line version banner. It is the responsibility of the caller * to make sure it gets freed. */ TCHAR *generateVersionBanner() { TCHAR *banner = TEXT("Java Service Wrapper %s Edition %s-bit %s\n Copyright (C) 1999-%s Tanuki Software, Ltd. All Rights Reserved.\n http://wrapper.tanukisoftware.com"); TCHAR *product = TEXT("Community"); TCHAR *copyright = TEXT("2014"); TCHAR *buffer; size_t len; len = _tcslen(banner) + _tcslen(product) + _tcslen(wrapperBits) + _tcslen(wrapperVersionRoot) + _tcslen(copyright) + 1; buffer = malloc(sizeof(TCHAR) * len); if (!buffer) { outOfMemory(TEXT("GVB"), 1); return NULL; } _sntprintf(buffer, len, banner, product, wrapperBits, wrapperVersionRoot, copyright); return buffer; } /** * Output the version. */ void wrapperVersionBanner() { TCHAR *banner = generateVersionBanner(); if (!banner) { return; } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, banner); free(banner); } /** * Output the application usage. */ void wrapperUsage(TCHAR *appName) { TCHAR *confFileBase; confFileBase = malloc(sizeof(TCHAR) * (_tcslen(appName) + 1)); if (!confFileBase) { outOfMemory(TEXT("WU"), 1); return; } wrapperGetFileBase(appName, confFileBase); setSimpleLogLevels(); wrapperVersionBanner(); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Usage:")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" %s [configuration properties] [...]"), appName); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" %s [configuration properties] [...]"), appName); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" ( implicitly '-c')")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" %s "), appName); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" ( implicitly '%s.conf')"), confFileBase); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" %s"), appName); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" ( implicitly '-c' and '%s.conf')"), confFileBase); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("where can be one of:")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -c --console run as a Console application")); #ifdef WIN32 log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -t --start starT an NT service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -a --pause pAuse a started NT service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -e --resume rEsume a paused NT service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -p --stop stoP a running NT service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -i --install Install as an NT service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -it --installstart Install and sTart as an NT service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -r --remove Uninstall/Remove as an NT service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -l= --controlcode= send a user controL Code to a running NT service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -d --dump request a thread Dump")); /** Return mask: installed:1 running:2 interactive:4 automatic:8 manual:16 disabled:32 */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -q --query Query the current status of the service")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -qs --querysilent Silently Query the current status of the service")); /* Omit '-s' option from help as it is only used by the service manager. */ /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -s --service used by service manager")); */ #endif log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -v --version print the wrapper's version information.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -? --help print this help message")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" -- mark the end of Wrapper arguments. All arguments after the\n '--' will be passed through unmodified to the java application.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" is the wrapper.conf to use. Name must be absolute or relative")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" to the location of %s"), appName); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("[configuration properties] are configuration name-value pairs which override values")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" in wrapper.conf. For example:")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" wrapper.debug=true")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Please note that any file references must be absolute or relative to the location\n of the Wrapper executable.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("")); free(confFileBase); } /** * Parse the main arguments. * * Returns FALSE if the application should exit with an error. A message will * already have been logged. */ int wrapperParseArguments(int argc, TCHAR **argv) { TCHAR *argConfFileBase; TCHAR *c; int delimiter, wrapperArgCount; wrapperData->javaArgValueCount = 0; delimiter = 1; if (argc > 1 ) { for (delimiter = 0; delimiter < argc ; delimiter++) { if ( _tcscmp(argv[delimiter], TEXT("--")) == 0) { #if !defined(WIN32) && defined(UNICODE) free(argv[delimiter]); #endif argv[delimiter] = NULL; wrapperData->javaArgValueCount = argc - delimiter - 1; if (delimiter + 1 < argc) { wrapperData->javaArgValues = &argv[delimiter + 1]; } break; } } } wrapperArgCount = delimiter ; if (wrapperArgCount > 1) { /* Store the name of the binary.*/ wrapperData->argBinary = argv[0]; if (argv[1][0] == TEXT('-')) { /* Syntax 1 or 3 */ /* A command appears to have been specified. */ wrapperData->argCommand = &argv[1][1]; /* Strip off the '-' */ if (wrapperData->argCommand[0] == TEXT('\0')) { wrapperUsage(argv[0]); return FALSE; } /* Does the argument have a value? */ c = _tcschr(wrapperData->argCommand, TEXT('=')); if (c == NULL) { wrapperData->argCommandArg = NULL; } else { wrapperData->argCommandArg = (TCHAR *)(c + 1); c[0] = TEXT('\0'); } if (wrapperArgCount > 2) { if (_tcsncmp(wrapperData->argCommand, TEXT("-translate"), 5) == 0) { if (wrapperArgCount > 3) { wrapperData->argConfFile = argv[3]; wrapperData->argCount = wrapperArgCount - 4; wrapperData->argValues = &argv[4]; } return TRUE; } /* Syntax 1 */ /* A command and conf file were specified. */ wrapperData->argConfFile = argv[2]; wrapperData->argCount = wrapperArgCount - 3; wrapperData->argValues = &argv[3]; } else { /* Syntax 3 */ /* Only a command was specified. Assume a default config file name. */ argConfFileBase = malloc(sizeof(TCHAR) * (_tcslen(argv[0]) + 1)); if (!argConfFileBase) { outOfMemory(TEXT("WPA"), 1); return FALSE; } wrapperGetFileBase(argv[0], argConfFileBase); /* The following malloc is only called once, but is never freed. */ wrapperData->argConfFile = malloc((_tcslen(argConfFileBase) + 5 + 1) * sizeof(TCHAR)); if (!wrapperData->argConfFile) { outOfMemory(TEXT("WPA"), 2); free(argConfFileBase); return FALSE; } _sntprintf(wrapperData->argConfFile, _tcslen(argConfFileBase) + 5 + 1, TEXT("%s.conf"), argConfFileBase); free(argConfFileBase); wrapperData->argConfFileDefault = TRUE; wrapperData->argCount = wrapperArgCount - 2; wrapperData->argValues = &argv[2]; } } else { /* Syntax 2 */ /* A command was not specified, but there may be a config file. */ wrapperData->argCommand = TEXT("c"); wrapperData->argCommandArg = NULL; wrapperData->argConfFile = argv[1]; wrapperData->argCount = wrapperArgCount - 2; wrapperData->argValues = &argv[2]; } } else { /* Systax 4 */ /* A config file was not specified. Assume a default config file name. */ wrapperData->argCommand = TEXT("c"); wrapperData->argCommandArg = NULL; argConfFileBase = malloc(sizeof(TCHAR) * (_tcslen(argv[0]) + 1)); if (!argConfFileBase) { outOfMemory(TEXT("WPA"), 3); return FALSE; } wrapperGetFileBase(argv[0], argConfFileBase); /* The following malloc is only called once, but is never freed. */ wrapperData->argConfFile = malloc((_tcslen(argConfFileBase) + 5 + 1) * sizeof(TCHAR)); if (!wrapperData->argConfFile) { outOfMemory(TEXT("WPA"), 4); free(argConfFileBase); return FALSE; } _sntprintf(wrapperData->argConfFile, _tcslen(argConfFileBase) + 5 + 1, TEXT("%s.conf"), argConfFileBase); free(argConfFileBase); wrapperData->argConfFileDefault = TRUE; wrapperData->argCount = wrapperArgCount - 1; wrapperData->argValues = &argv[1]; } return TRUE; } /** * Performs the specified action, * * @param actionList An array of action Ids ending with a value ACTION_LIST_END. * Negative values are standard actions, positive are user * custom events. * @param triggerMsg The reason the actions are being fired. * @param actionSourceCode Tracks where the action originated. * @param logForActionNone Flag stating whether or not a message should be logged * for the NONE action. * @param exitCode Error code to use in case the action results in a shutdown. */ void wrapperProcessActionList(int *actionList, const TCHAR *triggerMsg, int actionSourceCode, int logForActionNone, int exitCode) { int i; int action; if (actionList) { i = 0; while ((action = actionList[i]) != ACTION_LIST_END) { switch(action) { case ACTION_RESTART: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s %s"), triggerMsg, wrapperGetRestartProcessMessage()); wrapperRestartProcess(); break; case ACTION_SHUTDOWN: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s Shutting down."), triggerMsg); wrapperStopProcess(exitCode, FALSE); break; case ACTION_DUMP: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s Requesting thread dump."), triggerMsg); wrapperRequestDumpJVMState(); break; case ACTION_DEBUG: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s Debugging."), triggerMsg); break; case ACTION_PAUSE: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s Pausing..."), triggerMsg); wrapperPauseProcess(actionSourceCode); break; case ACTION_RESUME: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s Resuming..."), triggerMsg); wrapperResumeProcess(actionSourceCode); break; #if defined(MACOSX) case ACTION_ADVICE_NIL_SERVER: if (wrapperData->isAdviserEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT( "--------------------------------------------------------------------")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT( "Advice:")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT( "MACOSX is known to have problems displaying GUIs from processes\nrunning as a daemon launched from launchd. The above\n\"Returning nil _server\" means that you are encountering this\nproblem. This usually results in a long timeout which is affecting\nthe performance of your application.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT( "--------------------------------------------------------------------")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("")); } break; #endif case ACTION_NONE: if (logForActionNone) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s"), triggerMsg); } /* Do nothing but masks later filters */ break; case ACTION_SUCCESS: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s Application has signalled success, consider this application started successful..."), triggerMsg); wrapperData->failedInvocationCount = 0; break; case ACTION_GC: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s Requesting GC..."), triggerMsg); wrapperRequestJVMGC(actionSourceCode); break; default: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unknown action type: %d"), action); break; } i++; } } } /** * Function that will recursively attempt to match two strings where the * pattern can contain '?' or '*' wildcard characters. This function requires * that the pattern be matched from the beginning of the text. * * @param text Text to be searched. * @param textLen Length of the text. * @param pattern Pattern to search for. * @param patternLen Length of the pattern. * @param minTextLen Minimum number of characters that the text needs to possibly match the pattern. * * @return TRUE if found, FALSE otherwise. * * 1) text=abcdefg textLen=7 pattern=a*d*efg patternLen=7 minTextLen=5 * 1.1) text=bcdefg textLen=6 pattern=d*efg patternLen=5 minTextLen=4 * 1.2) text=cdefg textLen=5 pattern=d*efg patternLen=5 minTextLen=4 * 1.3) text=defg textLen=4 pattern=d*efg patternLen=5 minTextLen=4 * 1.3.1) text=efg textLen=3 pattern=efg patternLen=3 minTextLen=3 */ int wildcardMatchInner(const TCHAR *text, size_t textLen, const TCHAR *pattern, size_t patternLen, size_t minTextLen) { size_t textIndex; size_t patternIndex; TCHAR patternChar; size_t textIndex2; TCHAR textChar; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" wildcardMatchInner(\"%s\", %d, \"%s\", %d, %d)"), text, textLen, pattern, patternLen, minTextLen);*/ textIndex = 0; patternIndex = 0; while ((textIndex < textLen) && (patternIndex < patternLen)) { patternChar = pattern[patternIndex]; if (patternChar == TEXT('*')) { /* The pattern '*' can match 0 or more characters. This requires a bit of recursion to work it out. */ textIndex2 = textIndex; /* Loop over all possible starting locations. We know how many characters are needed to match (minTextLen - patternIndex) so we can stop there. */ while (textIndex2 < textLen - (minTextLen - (patternIndex + 1))) { if (wildcardMatchInner(&(text[textIndex2]), textLen - textIndex2, &(pattern[patternIndex + 1]), patternLen - (patternIndex + 1), minTextLen - patternIndex)) { /* Got a match in recursion. */ /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" wildcardMatchInner(\"%s\", %d, \"%s\", %d, %d) -> HERE1 textIndex=%d, patternIndex=%d, textIndex2=%d TRUE"), text, textLen, pattern, patternLen, minTextLen, textIndex, patternIndex, textIndex2);*/ return TRUE; } else { /* Failed to match. Try matching one more character against the '*'. */ textIndex2++; } } /* If we get here then all possible starting locations failed. */ /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" wildcardMatchInner(\"%s\", %d, \"%s\", %d, %d) -> HERE2 textIndex=%d, patternIndex=%d, textIndex2=%d FALSE"), text, textLen, pattern, patternLen, minTextLen, textIndex, patternIndex, textIndex2);*/ return FALSE; } else if (patternChar == TEXT('?')) { /* Match any character. */ patternIndex++; textIndex++; } else { textChar = text[textIndex]; if (patternChar == textChar) { /* Characters match. */ patternIndex++; textIndex++; } else { /* Characters do not match. We are done. */ /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" wildcardMatchInner(\"%s\", %d, \"%s\", %d, %d) -> HERE3 textIndex=%d, patternIndex=%d FALSE"), text, textLen, pattern, patternLen, minTextLen, textIndex, patternIndex);*/ return FALSE; } } } /* It is ok if there are text characters left over as we only need to match a substring, not the whole string. */ /* If there are any pattern chars left. Make sure that they are all wildcards. */ while (patternIndex < patternLen) { if (pattern[patternIndex] != TEXT('*')) { /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" wildcardMatchInner(\"%s\", %d, \"%s\", %d, %d) -> HERE4 pattern[%d]=%c FALSE"), text, textLen, pattern, patternLen, minTextLen, patternIndex, pattern[patternIndex]);*/ return FALSE; } patternIndex++; } /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" wildcardMatchInner(\"%s\", %d, \"%s\", %d, %d) -> HERE5 textIndex=%d, patternIndex=%d TRUE"), text, textLen, pattern, patternLen, minTextLen, textIndex, patternIndex);*/ return TRUE; } /** * Does any necessary post processing on the command string. * This function assumes that command has been malloced. It will either return * the string as is, or return a modified string. When a modified string is * returned the orignal command buffer will always be freed. * * 1) Replace the first instance of the %WRAPPER_COMMAND_FILLER_N% environment * variable so that the total command length will be equal to or greater than * the length specified by N. The padding will be the length plus a series of * Xs terminated by a single Y. This is mainly for testing. * * @param command The original command. * * @return The modifed command. */ TCHAR *wrapperPostProcessCommandElement(TCHAR *command) { TCHAR *pos1; TCHAR *pos2; size_t commandLen; size_t commandLen2; size_t commandLenLen; TCHAR commandLenBuffer[8]; size_t fillerLen; TCHAR *tempCommand; size_t index; /* If the special WRAPPER_COMMAND_FILLER_N environment variable is being used then expand it. * This is mainly used for testing. */ pos1 = _tcsstr(command, TEXT("%WRAPPER_COMMAND_FILLER_")); if (pos1 == NULL) { return command; } pos2 = _tcsstr(pos1 + 1, TEXT("%")); if (pos2 == NULL) { return command; } commandLen = _tcslen(command); commandLenLen = pos2 - pos1 - 24; if (commandLenLen >= 8) { /* Too long. invalid. */ return command; } memcpy(commandLenBuffer, pos1 + 24, sizeof(TCHAR) * commandLenLen); commandLenBuffer[commandLenLen] = TEXT('\0'); commandLen2 = __max((int)(commandLen - commandLenLen) - 25, __min(_ttoi(commandLenBuffer), 9999999)); fillerLen = commandLen2 - commandLen + commandLenLen + 25; tempCommand = malloc(sizeof(TCHAR) * (commandLen - commandLenLen - 25 + fillerLen + 1)); if (!tempCommand) { outOfMemory(TEXT("WBJC"), 3); return command; } memcpy(tempCommand, command, (pos1 - command) * sizeof(TCHAR)); index = pos1 - command; if (fillerLen > 11) { _sntprintf(&(tempCommand[index]), commandLen2 + 1 - index, TEXT("FILL-%d-"), fillerLen); fillerLen -= _tcslen(&tempCommand[index]); index += _tcslen(&tempCommand[index]); } while (fillerLen > 1) { tempCommand[index] = TEXT('X'); index++; fillerLen--; } if (fillerLen > 0) { tempCommand[index] = TEXT('Y'); index++; fillerLen--; } memcpy(&(tempCommand[index]), pos2 + 1, sizeof(TCHAR) * _tcslen(pos2 + 1)); tempCommand[commandLen2] = TEXT('\0'); free(command); return tempCommand; } /** * Test function to pause the current thread for the specified amount of time. * This is used to test how the rest of the Wrapper behaves when a particular * thread blocks for any reason. * * @param pauseTime Number of seconds to pause for. -1 will pause indefinitely. * @param threadName Name of the thread that will be logged prior to pausing. */ void wrapperPauseThread(int pauseTime, const TCHAR *threadName) { int i; if (pauseTime > 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Pausing the \"%s\" thread for %d seconds..."), threadName, pauseTime); for (i = 0; i < pauseTime; i++) { wrapperSleep(1000); } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Resuming the \"%s\" thread..."), threadName); } else if (pauseTime < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Pausing the \"%s\" thread indefinitely."), threadName); while(TRUE) { wrapperSleep(1000); } } } /** * Function that will recursively attempt to match two strings where the * pattern can contain '?' or '*' wildcard characters. * * @param text Text to be searched. * @param pattern Pattern to search for. * @param patternLen Length of the pattern. * @param minTextLen Minimum number of characters that the text needs to possibly match the pattern. * * @return TRUE if found, FALSE otherwise. */ int wrapperWildcardMatch(const TCHAR *text, const TCHAR *pattern, size_t minTextLen) { size_t textLen; size_t patternLen; size_t textIndex; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("wrapperWildcardMatch(\"%s\", \"%s\", %d)"), text, pattern, minTextLen);*/ textLen = _tcslen(text); if (textLen < minTextLen) { return FALSE; } patternLen = _tcslen(pattern); /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" textLen=%d, patternLen=%d"), textLen, patternLen);*/ textIndex = 0; while (textIndex <= textLen - minTextLen) { if (wildcardMatchInner(&(text[textIndex]), textLen - textIndex, pattern, patternLen, minTextLen)) { return TRUE; } textIndex++; } return FALSE; } /** * Calculates the minimum text length which could be matched by the specified pattern. * Patterns can contain '*' or '?' wildcards. * '*' matches 0 or more characters. * '?' matches exactly one character. * * @param pattern Pattern to calculate. * * @return The minimum text length of the pattern. */ size_t wrapperGetMinimumTextLengthForPattern(const TCHAR *pattern) { size_t patternLen; size_t patternIndex; size_t minLen; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("wrapperGetMinimumTextLengthForPattern(%s)"), pattern);*/ patternLen = _tcslen(pattern); minLen = 0; for (patternIndex = 0; patternIndex < patternLen; patternIndex++) { if (pattern[patternIndex] == TEXT('*')) { /* Matches 0 or more characters, so don't increment the minLen */ } else { minLen++; } } /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("wrapperGetMinimumTextLengthForPattern(%s) -> %d"), pattern, minLen);*/ return minLen; } void logApplyFilters(const TCHAR *log) { int i; const TCHAR *filter; const TCHAR *filterMessage; int matched; /* Look for output filters in the output. Only match the first. */ for (i = 0; i < wrapperData->outputFilterCount; i++) { if (_tcslen(wrapperData->outputFilters[i]) > 0) { /* The filter is defined. */ matched = FALSE; filter = wrapperData->outputFilters[i]; if (wrapperData->outputFilterAllowWildFlags[i]) { if (wrapperWildcardMatch(log, filter, wrapperData->outputFilterMinLens[i])) { matched = TRUE; } } else { /* Do a simple check to see if the pattern is found exactly as is. */ if (_tcsstr(log, filter)) { /* Found an exact match for the pattern. */ /* Any wildcards in the pattern can be matched exactly if they exist in the output. This is by design. */ matched = TRUE; } } if (matched) { filterMessage = wrapperData->outputFilterMessages[i]; if ((!filterMessage) || (_tcslen(filterMessage) <= 0)) { filterMessage = TEXT("Filter trigger matched."); } wrapperProcessActionList(wrapperData->outputFilterActionLists[i], filterMessage, WRAPPER_ACTION_SOURCE_CODE_FILTER, FALSE, 1); /* break out of the loop */ break; } } } } /** * Logs a single line of child output allowing any filtering * to be done in a common location. */ void logChildOutput(const char* log) { TCHAR* tlog; #ifdef UNICODE int size; #ifdef WIN32 TCHAR buffer[16]; UINT cp; #endif #endif #ifdef UNICODE #ifdef WIN32 GetLocaleInfo(GetThreadLocale(), LOCALE_IDEFAULTANSICODEPAGE, buffer, sizeof(buffer)); cp = _ttoi(buffer); size = MultiByteToWideChar(cp, 0, log, -1 , NULL, 0); if (size <= 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Invalid multibyte sequence in %s: %s"), TEXT("JVM console output"), getLastErrorText()); return; } tlog = (TCHAR*)malloc((size + 1) * sizeof(TCHAR)); if (!tlog) { outOfMemory(TEXT("WLCO"), 1); return; } MultiByteToWideChar(cp, 0, log, -1, tlog, size + 1); #else size = mbstowcs(NULL, log, MBSTOWCS_QUERY_LENGTH); if (size == (size_t)-1) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Invalid multibyte sequence in %s: %s"), TEXT("JVM console output"), getLastErrorText()); return; } tlog = malloc(sizeof(TCHAR) * (size + 1)); if (!tlog) { outOfMemory(TEXT("WLCO"), 1); return; } mbstowcs(tlog, log, size + 1); tlog[size] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ #endif #else tlog = (TCHAR*)log; #endif log_printf(wrapperData->jvmRestarts, LEVEL_INFO, tlog); /* Look for output filters in the output. Only match the first. */ logApplyFilters(tlog); #ifdef UNICODE free(tlog); #endif } /** * This function is for moving a buffer inside itself. * * This implementation exists because the standard memcpy is not reliable on * some platforms when the source and target buffer are the same. Most likely the * problem was caused by internal optimizations, but it was leading to crashes. */ void safeMemCpy(char *buffer, size_t target, size_t src, size_t nbyte) { size_t i; for (i = 0; i < nbyte; i++) { buffer[target + i] = buffer[src + i]; } } #define CHAR_LF 0x0a /** * Read and process any output from the child JVM Process. * * When maxTimeMS is non-zero this function will only be allowed to run for that maximum * amount of time. This is done to make sure the calling function is allowed CPU for * other activities. When timing out for this reason when there is more data in the * pipe, this function will return TRUE to let the calling code know that it should * not to any unnecessary sleeps. Otherwise FALSE will be returned. * * @param maxTimeMS The maximum number of milliseconds that this function will be allowed * to run without returning. In reality no new reads will happen after * this time, but actual processing may take longer. * * @return TRUE if the calling code should call this function again as soon as possible. */ int wrapperReadChildOutput(int maxTimeMS) { struct timeb timeBuffer; time_t startTime; int startTimeMillis; time_t now; int nowMillis; time_t durr; char *tempBuffer; char *cLF; int currentBlockRead; size_t loggedOffset; int defer = FALSE; int readThisPass = FALSE; if (!wrapperChildWorkBuffer) { /* Initialize the wrapperChildWorkBuffer. Set its initial size to the block size + 1. * This is so that we can always add a \0 to the end of it. */ wrapperChildWorkBuffer = malloc(sizeof(char) * ((READ_BUFFER_BLOCK_SIZE * 2) + 1)); if (!wrapperChildWorkBuffer) { outOfMemory(TEXT("WRCO"), 1); return FALSE; } wrapperChildWorkBufferSize = READ_BUFFER_BLOCK_SIZE * 2; } wrapperGetCurrentTime(&timeBuffer); startTime = now = timeBuffer.time; startTimeMillis = nowMillis = timeBuffer.millitm; #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("wrapperReadChildOutput() BEGIN")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("now=%ld, nowMillis=%d"), now, nowMillis); #endif /* Loop and read in CHILD_BLOCK_SIZE characters at a time. * * To keep a JVM outputting lots of content from freezing the Wrapper, we force a return every 250ms. */ while ((maxTimeMS <= 0) || ((durr = (now - startTime) * 1000 + (nowMillis - startTimeMillis)) < maxTimeMS)) { #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("durr=%ld"), durr); #endif /* If there is not enough space in the work buffer to read in a full block then it needs to be extended. */ if (wrapperChildWorkBufferLen + READ_BUFFER_BLOCK_SIZE > wrapperChildWorkBufferSize) { #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Expand buffer.")); #endif /* Increase the buffer quickly, but try not to get too big. Increase to a size that is the * greater of size + 1024 or size * 1.1. * Also make sure the new buffer is larger than the buffer len. This should not be necessary * but is safer. */ wrapperChildWorkBufferSize = __max(wrapperChildWorkBufferLen + 1, __max(wrapperChildWorkBufferSize + READ_BUFFER_BLOCK_SIZE, wrapperChildWorkBufferSize + wrapperChildWorkBufferSize / 10)); tempBuffer = malloc(wrapperChildWorkBufferSize + 1); if (!tempBuffer) { outOfMemory(TEXT("WRCO"), 2); return FALSE; } memcpy(tempBuffer, wrapperChildWorkBuffer, wrapperChildWorkBufferLen); tempBuffer[wrapperChildWorkBufferLen] = '\0'; free(wrapperChildWorkBuffer); wrapperChildWorkBuffer = tempBuffer; #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("buffer now %d bytes"), wrapperChildWorkBufferSize); #endif } #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Try reading from pipe. totalBuffLen=%d, buffSize=%d"), wrapperChildWorkBufferLen, wrapperChildWorkBufferSize); #endif if (wrapperReadChildOutputBlock(wrapperChildWorkBuffer + (wrapperChildWorkBufferLen), (int)(wrapperChildWorkBufferSize - wrapperChildWorkBufferLen), ¤tBlockRead)) { /* Error already reported. */ return FALSE; } if (currentBlockRead > 0) { /* We read in a block, so increase the length. */ wrapperChildWorkBufferLen += currentBlockRead; wrapperChildWorkLastDataTime = now; wrapperChildWorkLastDataTimeMillis = nowMillis; readThisPass = TRUE; #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" Read %d bytes of new output. totalBuffLen=%d, buffSize=%d"), currentBlockRead, wrapperChildWorkBufferLen, wrapperChildWorkBufferSize); #endif } /* Terminate the string just to avoid errors. The buffer has an extra character to handle this. */ wrapperChildWorkBuffer[wrapperChildWorkBufferLen] = '\0'; /* Loop over the contents of the buffer and try and extract as many lines as possible. * Keep track of where we are to avoid unnecessary memory copies. * At this point, the entire buffer will always be unlogged. */ loggedOffset = 0; defer = FALSE; while ((wrapperChildWorkBufferLen > loggedOffset) && (!defer)) { #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Inner loop. totalBuffLen=%d, loggedOffset=%d, unloggedBuffLen=%d, buffSize=%d"), wrapperChildWorkBufferLen, loggedOffset, wrapperChildWorkBufferLen - loggedOffset, wrapperChildWorkBufferSize); #endif /* We have something in the buffer. Loop and see if we have a complete line to log. * We will always find a LF at the end of the line. On Windows there may be a CR immediately before it. */ cLF = strchr(wrapperChildWorkBuffer + loggedOffset, (char)CHAR_LF); if (cLF != NULL) { /* We found a valid LF so we know that a full line is ready to be logged. */ #ifdef WIN32 if ((cLF > wrapperChildWorkBuffer) && ((cLF - sizeof(char))[0] == 0x0d)) { #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Found CR+LF")); #endif /* Replace the CR with a NULL */ (cLF - sizeof(char))[0] = 0; } else { #endif #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Found LF")); #endif #ifdef WIN32 } #endif /* Replace the LF with a NULL */ cLF[0] = '\0'; /* We have a string to log. */ #ifdef DEBUG_CHILD_OUTPUT #ifdef UNICODE /* It is not easy to log the string as is because they are not wide chars. Send it only to stdout. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Log: (see stdout)")); #ifdef WIN32 wprintf(TEXT("Log: [%S]\n"), wrapperChildWorkBuffer + loggedOffset); #else wprintf(TEXT("Log: [%s]\n"), wrapperChildWorkBuffer + loggedOffset); #endif #else log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Log: [%s]"), wrapperChildWorkBuffer + loggedOffset); #endif #endif /* Actually log the individual line of output. */ logChildOutput(wrapperChildWorkBuffer + loggedOffset); /* Update the offset so we know how far we've logged. */ loggedOffset = cLF - wrapperChildWorkBuffer + 1; #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("loggedOffset: %d"), loggedOffset); #endif } else { /* If we read this pass or if the last character is a CR on Windows then we always want to defer. */ if (readThisPass #ifdef WIN32 || (wrapperChildWorkBuffer[wrapperChildWorkBufferLen - 1] == 0x0d) #endif /* Avoid dumping partial lines because we call this funtion too quickly more than once. * Never let the line be partial unless more than the LF-Delay threshold has expired. */ || (wrapperData->logLFDelayThreshold == 0) || (((now - wrapperChildWorkLastDataTime) * 1000 + (nowMillis - wrapperChildWorkLastDataTimeMillis)) < wrapperData->logLFDelayThreshold) ) { #ifdef DEBUG_CHILD_OUTPUT #ifdef UNICODE /* It is not easy to log the string as is because they are not wide chars. Send it only to stdout. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Incomplete line. Defer: (see stdout) Age: %d"), (now - wrapperChildWorkLastDataTime) * 1000 + (nowMillis - wrapperChildWorkLastDataTimeMillis)); #ifdef WIN32 wprintf(TEXT("Defer Log: [%S]\n"), wrapperChildWorkBuffer + loggedOffset); #else wprintf(TEXT("Defer Log: [%s]\n"), wrapperChildWorkBuffer + loggedOffset); #endif #else log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Incomplete line. Defer: [%s] Age: %d"), wrapperChildWorkBuffer, (now - wrapperChildWorkLastDataTime) * 1000 + (nowMillis - wrapperChildWorkLastDataTimeMillis)); #endif #endif defer = TRUE; } else { /* We have an incomplete line, but it was from a previous pass and is old enough, so we want to log it as it may be a prompt. * This will always be the complete buffer. */ #ifdef DEBUG_CHILD_OUTPUT #ifdef UNICODE /* It is not easy to log the string as is because they are not wide chars. Send it only to stdout. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Incomplete line, but log now: (see stdout) Age: %d"), (now - wrapperChildWorkLastDataTime) * 1000 + (nowMillis - wrapperChildWorkLastDataTimeMillis)); #ifdef WIN32 wprintf(TEXT("Log: [%S]\n"), wrapperChildWorkBuffer + loggedOffset); #else wprintf(TEXT("Log: [%s]\n"), wrapperChildWorkBuffer + loggedOffset); #endif #else log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Incomplete line, but log now: [%s] Age: %d"), wrapperChildWorkBuffer, (now - wrapperChildWorkLastDataTime) * 1000 + (nowMillis - wrapperChildWorkLastDataTimeMillis)); #endif #endif logChildOutput(wrapperChildWorkBuffer + loggedOffset); /* We know we read everything so we can safely reset the loggedOffset and clear the buffer. */ wrapperChildWorkBuffer[0] = '\0'; wrapperChildWorkBufferLen = 0; loggedOffset = 0; } } } /* We have read as many lines from the buffered output as possible. * If we still have any partial lines, then we need to make sure they are moved to the beginning of the buffer so we can read in another block. */ if (loggedOffset > 0) { if (loggedOffset >= wrapperChildWorkBufferLen) { /* We know we have read everything in. So we can efficiently clear the buffer. */ #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Cleared Buffer as everything was logged.")); #endif wrapperChildWorkBuffer[0] = '\0'; wrapperChildWorkBufferLen = 0; /* loggedOffset = 0; Not needed. */ } else { /* We have logged one or more lines from the buffer, but unlogged content still exists. It needs to be moved to the head of the buffer. */ #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Moving %d bytes in buffer for next cycle."), wrapperChildWorkBufferLen - loggedOffset); #endif /* NOTE - This line intentionally does the copy within the same memory space. It is safe the way it is working however. */ wrapperChildWorkBufferLen = wrapperChildWorkBufferLen - loggedOffset; safeMemCpy(wrapperChildWorkBuffer, 0, loggedOffset, wrapperChildWorkBufferLen); /* Shouldn't be needed, but just to make sure the buffer has been ended properly */ wrapperChildWorkBuffer[wrapperChildWorkBufferLen] = 0; /* loggedOffset = 0; Not needed. */ } } else { } if (currentBlockRead <= 0) { /* All done for now. */ if (wrapperChildWorkBufferLen > 0) { #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("wrapperReadChildOutput() END (Incomplete)")); #endif } else { #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("wrapperReadChildOutput() END")); #endif } return FALSE; } /* Get the time again */ wrapperGetCurrentTime(&timeBuffer); now = timeBuffer.time; nowMillis = timeBuffer.millitm; } /* If we got here then we timed out. */ #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("wrapperReadChildOutput() END TIMEOUT")); #endif return TRUE; } /** * Immediately after a JVM is launched and whenever the log file name changes, * the log file name is sent to the JVM where it can be referenced by applications. */ void sendLogFileName() { TCHAR *currentLogFilePath; currentLogFilePath = getCurrentLogfilePath(); if (currentLogFilePath) { wrapperProtocolFunction(WRAPPER_MSG_LOGFILE, currentLogFilePath); free(currentLogFilePath); } } /** * Immediately after a JVM is launched, the wrapper configuration is sent to the * JVM where it can be used as a properties object. */ void sendProperties() { TCHAR *buffer; buffer = linearizeProperties(properties, TEXT('\t')); if (buffer) { wrapperProtocolFunction(WRAPPER_MSG_PROPERTIES, buffer); free(buffer); } } /** * Common cleanup code which should get called when we first decide that the JVM was down. */ void wrapperJVMDownCleanup(int setState) { /* Only set the state to DOWN_CHECK if we are not already in a state which reflects this. */ if (setState) { if (wrapperData->jvmCleanupTimeout > 0) { wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CHECK, wrapperGetTicks(), wrapperData->jvmCleanupTimeout); } else { wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CHECK, wrapperGetTicks(), -1); } } /* Remove java pid file if it was registered and created by this process. */ if (wrapperData->javaPidFilename) { _tunlink(wrapperData->javaPidFilename); } #ifdef WIN32 if (!CloseHandle(wrapperData->javaProcess)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to close the Java process handle: %s"), getLastErrorText()); } wrapperData->javaProcess = NULL; #endif /* Close any open socket to the JVM */ if (wrapperData->stoppedPacketReceived) { wrapperProtocolClose(); } else { /* Leave the socket open so the Wrapper has the chance to read any outstanding packets. */ } } /** * Immediately kill the JVM process and set the JVM state to * WRAPPER_JSTATE_DOWN_CHECK. */ int wrapperKillProcessNow() { #ifdef WIN32 int ret; #endif /* Check to make sure that the JVM process is still running */ #ifdef WIN32 ret = WaitForSingleObject(wrapperData->javaProcess, 0); if (ret == WAIT_TIMEOUT) { #else if (waitpid(wrapperData->javaPID, NULL, WNOHANG) == 0) { #endif /* JVM is still up when it should have already stopped itself. */ /* The JVM process is not responding so the only choice we have is to * kill it. */ #ifdef WIN32 /* The TerminateProcess funtion will kill the process, but it * does not correctly notify the process's DLLs that it is shutting * down. Ideally, we would call ExitProcess, but that can only be * called from within the process being killed. */ if (TerminateProcess(wrapperData->javaProcess, 0)) { #else if (kill(wrapperData->javaPID, SIGKILL) == 0) { #endif log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("JVM did not exit on request, termination requested.")); return FALSE; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("JVM did not exit on request.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT(" Attempt to terminate process failed: %s"), getLastErrorText()); /* Terminating the current JVM failed. Cancel pending restart requests */ wrapperJVMDownCleanup(TRUE); wrapperData->exitCode = 1; return TRUE; } } wrapperJVMDownCleanup(TRUE); return FALSE; } /** * Puts the Wrapper into a state where the JVM will be killed at the soonest * possible opportunity. It is necessary to wait a moment if a final thread * dump is to be requested. This call wll always set the JVM state to * WRAPPER_JSTATE_KILLING. */ void wrapperKillProcess() { #ifdef WIN32 int ret; #endif int delay = 0; if ((wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) || (wrapperData->jState == WRAPPER_JSTATE_LAUNCH_DELAY) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH)) { /* Already down. */ if (wrapperData->jState == WRAPPER_JSTATE_LAUNCH_DELAY) { wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, wrapperGetTicks(), 0); } return; } /* Check to make sure that the JVM process is still running */ #ifdef WIN32 ret = WaitForSingleObject(wrapperData->javaProcess, 0); if (ret == WAIT_TIMEOUT) { #else if (waitpid(wrapperData->javaPID, NULL, WNOHANG) == 0) { #endif /* JVM is still up when it should have already stopped itself. */ if (wrapperData->requestThreadDumpOnFailedJVMExit) { wrapperRequestDumpJVMState(); delay = wrapperData->requestThreadDumpOnFailedJVMExitDelay; } } wrapperSetJavaState(WRAPPER_JSTATE_KILLING, wrapperGetTicks(), delay); } /** * Add some checks of the properties to try to catch the case where the user is making use of TestWrapper scripts. * * @return TRUE if there is such a missconfiguration. FALSE if all is Ok. */ int checkForTestWrapperScripts() { const TCHAR* prop; prop = getStringProperty(properties, TEXT("wrapper.java.mainclass"), NULL); if (prop) { if (_tcscmp(prop, TEXT("org.tanukisoftware.wrapper.test.Main")) == 0) { /* This is the TestWrapper app. So don't check. */ } else { /* This is a user application, so make sure that they are not using the TestWrapper scripts. */ prop = getStringProperty(properties, TEXT("wrapper.app.parameter.2"), NULL); if (prop) { if (_tcscmp(prop, TEXT("{{TestWrapperBat}}")) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "--------------------------------------------------------------------")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "We have detected that you are making use of the sample batch files\nthat are designed for the TestWrapper Example Application. When\nsetting up your own application, please copy fresh files over from\nthe Wrapper's src\\bin directory.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Shutting down as this will likely cause problems with your\napplication startup.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Please see the integration section of the documentation for more\ninformation.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( " http://wrapper.tanukisoftware.com/integrate")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "--------------------------------------------------------------------")); return TRUE; } else if (_tcscmp(prop, TEXT("{{TestWrapperSh}}")) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "--------------------------------------------------------------------")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "We have detected that you are making use of the sample shell scripts\nthat are designed for the TestWrapper Example Application. When\nsetting up your own application, please copy fresh files over from\nthe Wrapper's src/bin directory.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Shutting down as this will likely cause problems with your\napplication startup.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Please see the integration section of the documentation for more\ninformation.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( " http://wrapper.tanukisoftware.com/integrate")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "--------------------------------------------------------------------")); return TRUE; } } } } return FALSE; } #ifdef WIN32 #define OSBUFSIZE 256 /** * Creates a human readable representation of the Windows OS the Wrapper is run on. * * @param pszOS the buffer the information gets stored to * @return FALSE if error or no information could be retrieved. TRUE otherwise. */ BOOL GetOSDisplayString(TCHAR** pszOS) { OSVERSIONINFOEX osvi; SYSTEM_INFO si; FARPROC pGNSI; FARPROC pGPI; DWORD dwType; TCHAR buf[80]; ZeroMemory(&si, sizeof(SYSTEM_INFO)); ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!GetVersionEx((OSVERSIONINFO*) &osvi)) { return FALSE; } /* Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.*/ pGNSI = GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); if (NULL != pGNSI) { pGNSI(&si); } else { GetSystemInfo(&si); } if ((VER_PLATFORM_WIN32_NT == osvi.dwPlatformId) && (osvi.dwMajorVersion > 4)) { _tcsncpy(*pszOS, TEXT("Microsoft "), OSBUFSIZE); /* Test for the specific product. */ if (osvi.dwMajorVersion == 6) { if (osvi.dwMinorVersion == 0 ) { if (osvi.wProductType == VER_NT_WORKSTATION) { _tcsncat(*pszOS, TEXT("Windows Vista "), OSBUFSIZE); } else { _tcsncat(*pszOS, TEXT("Windows Server 2008 "), OSBUFSIZE); } } if (osvi.dwMinorVersion == 1) { if (osvi.wProductType == VER_NT_WORKSTATION) { _tcsncat(*pszOS, TEXT("Windows 7 "), OSBUFSIZE); } else { _tcsncat(*pszOS, TEXT("Windows Server 2008 R2 "), OSBUFSIZE); } } pGPI = GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo"); pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType); switch (dwType) { case 1: _tcsncat(*pszOS, TEXT("Ultimate Edition" ), OSBUFSIZE); break; case 48: _tcsncat(*pszOS, TEXT("Professional"), OSBUFSIZE); break; case 3: _tcsncat(*pszOS, TEXT("Home Premium Edition"), OSBUFSIZE); break; case 67: _tcsncat(*pszOS, TEXT("Home Basic Edition"), OSBUFSIZE); break; case 4: _tcsncat(*pszOS, TEXT("Enterprise Edition"), OSBUFSIZE); break; case 6: _tcsncat(*pszOS, TEXT("Business Edition"), OSBUFSIZE); break; case 11: _tcsncat(*pszOS, TEXT("Starter Edition"), OSBUFSIZE); break; case 18: _tcsncat(*pszOS, TEXT("Cluster Server Edition"), OSBUFSIZE); break; case 8: _tcsncat(*pszOS, TEXT("Datacenter Edition"), OSBUFSIZE); break; case 12: _tcsncat(*pszOS, TEXT("Datacenter Edition (core installation)"), OSBUFSIZE); break; case 10: _tcsncat(*pszOS, TEXT("Enterprise Edition"), OSBUFSIZE); break; case 14: _tcsncat(*pszOS, TEXT("Enterprise Edition (core installation)"), OSBUFSIZE); break; case 15: _tcsncat(*pszOS, TEXT("Enterprise Edition for Itanium-based Systems"), OSBUFSIZE); break; case 9: _tcsncat(*pszOS, TEXT("Small Business Server"), OSBUFSIZE); break; case 25: _tcsncat(*pszOS, TEXT("Small Business Server Premium Edition"), OSBUFSIZE); break; case 7: _tcsncat(*pszOS, TEXT("Standard Edition"), OSBUFSIZE); break; case 13: _tcsncat(*pszOS, TEXT("Standard Edition (core installation)"), OSBUFSIZE); break; case 17: _tcsncat(*pszOS, TEXT("Web Server Edition"), OSBUFSIZE); break; } } if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2)) { if (GetSystemMetrics(89)) { _tcsncat(*pszOS, TEXT("Windows Server 2003 R2, "), OSBUFSIZE); } else if (osvi.wSuiteMask & 8192) { _tcsncat(*pszOS, TEXT("Windows Storage Server 2003"), OSBUFSIZE); } else if (osvi.wSuiteMask & 32768) { _tcsncat(*pszOS, TEXT("Windows Home Server"), OSBUFSIZE); } else if (osvi.wProductType == VER_NT_WORKSTATION && si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) { _tcsncat(*pszOS, TEXT("Windows XP Professional x64 Edition"), OSBUFSIZE); } else { _tcsncat(*pszOS, TEXT("Windows Server 2003, "), OSBUFSIZE); } /* Test for the server type. */ if (osvi.wProductType != VER_NT_WORKSTATION) { if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) { if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { _tcsncat(*pszOS, TEXT("Datacenter Edition for Itanium-based Systems"), OSBUFSIZE); } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { _tcsncat(*pszOS, TEXT("Enterprise Edition for Itanium-based Systems"), OSBUFSIZE); } } else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { _tcsncat(*pszOS, TEXT("Datacenter x64 Edition"), OSBUFSIZE); } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { _tcsncat(*pszOS, TEXT("Enterprise x64 Edition"), OSBUFSIZE); } else { _tcsncat(*pszOS, TEXT("Standard x64 Edition"), OSBUFSIZE); } } else { if (osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER) { _tcsncat(*pszOS, TEXT("Compute Cluster Edition"), OSBUFSIZE); } else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { _tcsncat(*pszOS, TEXT("Datacenter Edition"), OSBUFSIZE); } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { _tcsncat(*pszOS, TEXT("Enterprise Edition"), OSBUFSIZE); } else if (osvi.wSuiteMask & VER_SUITE_BLADE) { _tcsncat(*pszOS, TEXT("Web Edition" ), OSBUFSIZE); } else { _tcsncat(*pszOS, TEXT("Standard Edition"), OSBUFSIZE); } } } } if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1)) { _tcsncat(*pszOS, TEXT("Windows XP "), OSBUFSIZE); if (osvi.wSuiteMask & VER_SUITE_PERSONAL) { _tcsncat(*pszOS, TEXT("Home Edition"), OSBUFSIZE); } else { _tcsncat(*pszOS, TEXT("Professional"), OSBUFSIZE); } } if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) { _tcsncat(*pszOS, TEXT("Windows 2000 "), OSBUFSIZE); if (osvi.wProductType == VER_NT_WORKSTATION) { _tcsncat(*pszOS, TEXT("Professional"), OSBUFSIZE); } else { if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { _tcsncat(*pszOS, TEXT("Datacenter Server"), OSBUFSIZE); } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { _tcsncat(*pszOS, TEXT("Advanced Server"), OSBUFSIZE); } else { _tcsncat(*pszOS, TEXT("Server"), OSBUFSIZE); } } } /* Include service pack (if any) and build number. */ if (_tcslen(osvi.szCSDVersion) > 0) { _tcsncat(*pszOS, TEXT(" "), OSBUFSIZE); _tcsncat(*pszOS, osvi.szCSDVersion, OSBUFSIZE); } _sntprintf(buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber); _tcsncat(*pszOS, buf, OSBUFSIZE); if (osvi.dwMajorVersion >= 6) { if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { _tcsncat(*pszOS, TEXT(", 64-bit"), OSBUFSIZE); } else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { _tcsncat(*pszOS, TEXT(", 32-bit"), OSBUFSIZE); } } return TRUE; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Unknown Windows Version")); return FALSE; } } #endif /** * Launch common setup code. */ int wrapperRunCommonInner() { const TCHAR *prop; #ifdef WIN32 TCHAR* szOS; #endif struct tm timeTM; TCHAR* tz1; TCHAR* tz2; #if defined(UNICODE) size_t req; #endif /* Make sure the tick timer is working correctly. */ if (wrapperTickAssertions()) { return 1; } /* Log a startup banner. */ wrapperVersionBanner(); /* The following code will display a licensed to block if a license key is found * in the Wrapper configuration. This piece of code is required as is for * Development License owners to be in complience with their development license. * This code does not do any validation of the license keys and works differently * from the license code found in the Standard and Professional Editions of the * Wrapper. */ prop = getStringProperty(properties, TEXT("wrapper.license.type"), TEXT("")); if (strcmpIgnoreCase(prop, TEXT("DEV")) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Licensed to %s for %s"), getStringProperty(properties, TEXT("wrapper.license.licensee"), TEXT("(LICENSE INVALID)")), getStringProperty(properties, TEXT("wrapper.license.dev_application"), TEXT("(LICENSE INVALID)"))); } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("")); if (checkForTestWrapperScripts()) { return 1; } #ifdef WIN32 if (initializeStartup()) { return 1; } #endif if (wrapperData->isDebugging) { timeTM = wrapperGetReleaseTime(); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Release time: %04d/%02d/%02d %02d:%02d:%02d"), timeTM.tm_year + 1900, timeTM.tm_mon + 1, timeTM.tm_mday, timeTM.tm_hour, timeTM.tm_min, timeTM.tm_sec ); timeTM = wrapperGetBuildTime(); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Build time: %04d/%02d/%02d %02d:%02d:%02d"), timeTM.tm_year + 1900, timeTM.tm_mon + 1, timeTM.tm_mday, timeTM.tm_hour, timeTM.tm_min, timeTM.tm_sec ); /* Display timezone information. */ tzset(); #if defined(UNICODE) #if !defined(WIN32) req = mbstowcs(NULL, tzname[0], MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { return 1; } tz1 = malloc(sizeof(TCHAR) * (req + 1)); if (!tz1) { outOfMemory(TEXT("LHN"), 1); } else { mbstowcs(tz1, tzname[0], req + 1); tz1[req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ req = mbstowcs(NULL, tzname[1], MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { free(tz1); return 1; } tz2 = malloc(sizeof(TCHAR) * (req + 1)); if (!tz2) { outOfMemory(TEXT("LHN"), 2); free(tz1); } else { mbstowcs(tz2, tzname[1], req + 1); tz2[req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ #else req = MultiByteToWideChar(CP_OEMCP, 0, tzname[0], -1, NULL, 0); if (req <= 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Invalid multibyte sequence in port address \"%s\" : %s"), tzname[0], getLastErrorText()); return 1; } tz1 = malloc((req + 1) * sizeof(TCHAR)); if (!tz1) { outOfMemory(TEXT("LHN"), 1); } else { MultiByteToWideChar(CP_OEMCP,0, tzname[0], -1, tz1, (int)req + 1); req = MultiByteToWideChar(CP_OEMCP, 0, tzname[1], -1, NULL, 0); if (req <= 0) { free(tz1); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Invalid multibyte sequence in port address \"%s\" : %s"), tzname[1], getLastErrorText()); return 1; } tz2 = malloc((req + 1) * sizeof(TCHAR)); if (!tz2) { free(tz1); outOfMemory(TEXT("LHN"), 2); } else { MultiByteToWideChar(CP_OEMCP,0, tzname[1], -1, tz2, (int)req + 1); #endif #else tz1 = tzname[0]; tz2 = tzname[1]; #endif #ifndef FREEBSD log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Timezone: %s (%s) Offset: %ld, hasDaylight: %d"), tz1, tz2, timezone, daylight); #else log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Timezone: %s (%s) Offset: %ld"), tz1, tz2, timezone); #endif if (wrapperData->useSystemTime) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Using system timer.")); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Using tick timer.")); } #ifdef UNICODE free(tz1); free(tz2); } } #endif } #ifdef WIN32 if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Current User: %s Domain: %s"), (wrapperData->userName ? wrapperData->userName : TEXT("N/A")), (wrapperData->domainName ? wrapperData->domainName : TEXT("N/A"))); szOS = calloc(OSBUFSIZE, sizeof(TCHAR)); if (szOS) { if (GetOSDisplayString(&szOS)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Operating System ID: %s"), szOS); } free(szOS); } if (isCygwin()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Cygwin detected")); } } #endif /* Should we dump the environment variables? * If the the user specifically wants the environment, show it as the status log level, otherwise include it in debug output if enabled. */ if (getBooleanProperty(properties, TEXT("wrapper.environment.dump"), FALSE)) { dumpEnvironment(LEVEL_INFO); } else if (getBooleanProperty(properties, TEXT("wrapper.debug"), FALSE)) { dumpEnvironment(LEVEL_DEBUG); } #ifdef _DEBUG /* Multi-line logging tests. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("----- Should be 5 lines -----")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("\nLINE2:\n\nLINE4:\n")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("----- Next is one line ------")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("----- Next is two lines -----")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("\n")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("----- Next is two lines -----")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("ABC\nDEF")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("-----------------------------")); #endif #ifdef WRAPPER_FILE_DEBUG wrapperFileTests(); #endif return 0; } int wrapperRunCommon(const TCHAR *runMode) { int exitCode; /* Setup the wrapperData structure. */ wrapperSetWrapperState(WRAPPER_WSTATE_STARTING); wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, 0, -1); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("--> Wrapper Started as %s"), runMode); /* Initialize the wrapper */ exitCode = wrapperInitializeRun(); if (exitCode == 0) { if (!wrapperRunCommonInner()) { /* Enter main event loop */ wrapperEventLoop(); /* Clean up any open sockets. */ wrapperProtocolClose(); protocolStopServer(); exitCode = wrapperData->exitCode; } else { exitCode = 1; } } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("<-- Wrapper Stopped")); return exitCode; } /** * Launch the wrapper as a console application. */ int wrapperRunConsole() { return wrapperRunCommon(TEXT("Console")); } /** * Launch the wrapper as a service application. */ int wrapperRunService() { return wrapperRunCommon( #ifdef WIN32 TEXT("Service") #else TEXT("Daemon") #endif ); } /** * Used to ask the state engine to shut down the JVM and Wrapper. * * @param exitCode Exit code to use when shutting down. * @param force True to force the Wrapper to shutdown even if some configuration * had previously asked that the JVM be restarted. This will reset * any existing restart requests, but it will still be possible for * later actions to request a restart. */ void wrapperStopProcess(int exitCode, int force) { /* If we are are not aready shutting down, then do so. */ if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("wrapperStopProcess(%d, %s) called while stopping. (IGNORED)"), exitCode, (force ? TEXT("TRUE") : TEXT("FALSE"))); } } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("wrapperStopProcess(%d, %s) called."), exitCode, (force ? TEXT("TRUE") : TEXT("FALSE"))); } /* If it has not already been set, set the exit request flag. */ if (wrapperData->exitRequested || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) || (wrapperData->jState == WRAPPER_JSTATE_STOP) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED) || (wrapperData->jState == WRAPPER_JSTATE_KILLING) || (wrapperData->jState == WRAPPER_JSTATE_KILLED) || (wrapperData->jState == WRAPPER_JSTATE_KILL) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH)) { /* JVM is already down or going down. */ } else { wrapperData->exitRequested = TRUE; } wrapperData->exitCode = exitCode; if (force) { /* Make sure that further restarts are disabled. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_NO; /* Do not call wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING) here. * It will be called by the wrappereventloop.c.jStateDown once the * the JVM is completely down. Calling it here will make it * impossible to trap and restart based on exit codes or other * Wrapper configurations. */ if (wrapperData->isDebugging) { if ((wrapperData->restartRequested == WRAPPER_RESTART_REQUESTED_AUTOMATIC) || (wrapperData->restartRequested == WRAPPER_RESTART_REQUESTED_CONFIGURED)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" Overriding request to restart JVM.")); } } } else { /* Do not call wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING) here. * It will be called by the wrappereventloop.c.jStateDown once the * the JVM is completely down. Calling it here will make it * impossible to trap and restart based on exit codes. */ if (wrapperData->isDebugging) { if ((wrapperData->restartRequested == WRAPPER_RESTART_REQUESTED_AUTOMATIC) || (wrapperData->restartRequested == WRAPPER_RESTART_REQUESTED_CONFIGURED)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" Stop ignored. Continuing to restart JVM.")); } } } } } /** * Depending on the current state, we want to change the exact message displayed when restarting the JVM. * * The logic here needs to match that in wrapperRestartProcess. */ const TCHAR *wrapperGetRestartProcessMessage() { if ((wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) || (wrapperData->jState == WRAPPER_JSTATE_STOP) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED) || (wrapperData->jState == WRAPPER_JSTATE_KILLING) || (wrapperData->jState == WRAPPER_JSTATE_KILL) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH) || (wrapperData->jState == WRAPPER_JSTATE_LAUNCH_DELAY)) { if (wrapperData->restartRequested || (wrapperData->jState == WRAPPER_JSTATE_LAUNCH_DELAY)) { return TEXT("Restart JVM (Ignoring, already restarting)."); } else { return TEXT("Restart JVM (Ignoring, already shutting down)."); } } else if (wrapperData->exitRequested || wrapperData->restartRequested) { return TEXT("Restart JVM (Ignoring, already restarting)."); } else { return TEXT("Restarting JVM."); } } /** * Used to ask the state engine to shut down the JVM. This are always intentional restart requests. */ void wrapperRestartProcess() { /* If it has not already been set, set the restart request flag in the wrapper data. */ if (wrapperData->exitRequested || wrapperData->restartRequested || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) || (wrapperData->jState == WRAPPER_JSTATE_STOP) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED) || (wrapperData->jState == WRAPPER_JSTATE_KILLING) || (wrapperData->jState == WRAPPER_JSTATE_KILL) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH) || (wrapperData->jState == WRAPPER_JSTATE_LAUNCH_DELAY)) { /* Down but not yet restarted. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("wrapperRestartProcess() called. (IGNORED)")); } } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("wrapperRestartProcess() called.")); } wrapperData->exitRequested = TRUE; wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_CONFIGURED; } } /** * Used to ask the state engine to pause the JVM. * * @param actionSourceCode Tracks where the action originated. */ void wrapperPauseProcess(int actionSourceCode) { TCHAR msgBuffer[10]; if (!wrapperData->pausable) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperPauseProcess() called but wrapper.pausable is FALSE. (IGNORED)")); } return; } if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { /* If we are already shutting down, then ignore and continue to do so. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperPauseProcess() called while stopping. (IGNORED)")); } } else if (wrapperData->wState == WRAPPER_WSTATE_PAUSING) { /* If we are currently being paused, then ignore and continue to do so. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperPauseProcess() called while pausing. (IGNORED)")); } } else if (wrapperData->wState == WRAPPER_WSTATE_PAUSED) { /* If we are currently paused, then ignore and continue to do so. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperPauseProcess() called while paused. (IGNORED)")); } } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperPauseProcess() called.")); } wrapperSetWrapperState(WRAPPER_WSTATE_PAUSING); if (!wrapperData->pausableStopJVM) { /* Notify the Java process. */ _sntprintf(msgBuffer, 10, TEXT("%d"), actionSourceCode); wrapperProtocolFunction(WRAPPER_MSG_PAUSE, msgBuffer); } } } /** * Used to ask the state engine to resume a paused the JVM. * * @param actionSourceCode Tracks where the action originated. */ void wrapperResumeProcess(int actionSourceCode) { TCHAR msgBuffer[10]; if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { /* If we are already shutting down, then ignore and continue to do so. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperResumeProcess() called while stopping. (IGNORED)")); } } else if (wrapperData->wState == WRAPPER_WSTATE_STARTING) { /* If we are currently being started, then ignore and continue to do so. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperResumeProcess() called while starting. (IGNORED)")); } } else if (wrapperData->wState == WRAPPER_WSTATE_STARTED) { /* If we are currently started, then ignore and continue to do so. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperResumeProcess() called while started. (IGNORED)")); } } else if (wrapperData->wState == WRAPPER_WSTATE_RESUMING) { /* If we are currently being continued, then ignore and continue to do so. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperResumeProcess() called while resuming. (IGNORED)")); } } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "wrapperResumeProcess() called.")); } /* If we were configured to stop the JVM then we want to reset its failed * invocation count as the current stoppage was expected. */ if (wrapperData->pausableStopJVM) { wrapperData->failedInvocationCount = 0; } wrapperSetWrapperState(WRAPPER_WSTATE_RESUMING); if (!wrapperData->pausableStopJVM) { /* Notify the Java process. */ _sntprintf(msgBuffer, 10, TEXT("%d"), actionSourceCode); wrapperProtocolFunction(WRAPPER_MSG_RESUME, msgBuffer); } } } /** * Sends a command off to the JVM asking it to perform a garbage collection sweep. * * @param actionSourceCode Tracks where the action originated. */ void wrapperRequestJVMGC(int actionSourceCode) { TCHAR msgBuffer[10]; /* Notify the Java process. */ _sntprintf(msgBuffer, 10, TEXT("%d"), actionSourceCode); wrapperProtocolFunction(WRAPPER_MSG_GC, msgBuffer); } /** * Loops over and strips all double quotes from prop and places the * stripped version into propStripped. * * The exception is double quotes that are preceeded by a backslash * in this case the backslash is stripped. * * If two backslashes are found in a row, then the first escapes the * second and the second is removed. */ static size_t wrapperStripQuotesInner(const TCHAR *prop, size_t propLen, TCHAR *propStripped) { size_t len; int i, j; len = propLen; j = 0; for (i = 0; i < (int)len; i++) { if ((prop[i] == TEXT('\\')) && (i < (int)len - 1)) { if (prop[i + 1] == TEXT('\\')) { /* Double backslash. Keep the first, and skip the second. */ propStripped[j] = prop[i]; j++; i++; } else if (prop[i + 1] == TEXT('\"')) { /* Escaped quote. Keep the quote. */ propStripped[j] = prop[i + 1]; j++; i++; } else { /* Include the backslash as normal. */ propStripped[j] = prop[i]; j++; } } else if (prop[i] == TEXT('\"')) { /* Quote. Skip it. */ } else { propStripped[j] = prop[i]; j++; } } return j; } /** * Stripped quotes out of the prop argument. * The resulting value in propStripped will always be equal or shorter in length * so the propStripped buffer should always be equal to the prop buffer in length. */ void wrapperStripQuotes(const TCHAR *prop, TCHAR *propStripped) { size_t len; len = wrapperStripQuotesInner(prop, _tcslen(prop), propStripped); propStripped[len] = TEXT('\0'); } /** * Adds quotes around the specified string in such a way that everything is * escaped correctly. If the bufferSize is not large enough then the * required size will be returned. 0 is returned if successful. */ size_t wrapperQuoteValue(const TCHAR* value, TCHAR *buffer, size_t bufferSize) { size_t len = _tcslen(value); size_t in = 0; size_t out = 0; size_t in2; int escape; /* Initial quote. */ if (out < bufferSize) { buffer[out] = TEXT('"'); } out++; /* Copy over characters of value. */ while ((in < len) && (value[in] != TEXT('\0'))) { escape = FALSE; if (value[in] == TEXT('\\')) { /* All '\' characters in a row prior to a '"' or the end of the string need to be * escaped */ in2 = in + 1; while ((in2 < len) && (value[in2] == TEXT('\\'))) { in2++; } escape = ((in2 >= len) || (value[in2] == TEXT('"'))); } else if (value[in] == TEXT('"')) { escape = TRUE; } if (escape) { /* Needs to be escaped. */ if (out < bufferSize) { buffer[out] = TEXT('\\'); } out++; } if (out < bufferSize) { buffer[out] = value[in]; } out++; in++; } /* Trailing quote. */ if (out < bufferSize) { buffer[out] = TEXT('"'); } out++; /* Null terminate. */ if (out < bufferSize) { buffer[out] = TEXT('\0'); } out++; if (out <= bufferSize) { return 0; } else { return out; } } /** * Checks the quotes in the value and displays an error if there are any problems. * This can be useful to help users debug quote problems. */ int wrapperCheckQuotes(const TCHAR *value, const TCHAR *propName) { size_t len = _tcslen(value); size_t in = 0; size_t in2 = 0; int inQuote = FALSE; int escaped; while (in < len) { if (value[in] == TEXT('"')) { /* Decide whether or not this '"' is escaped. */ in2 = in - 1; escaped = FALSE; while (value[in2] == TEXT('\\')) { escaped = !escaped; if (in2 > 0) { in2--; } else { break; } } if (!escaped) { inQuote = !inQuote; } } else if (inQuote) { /* Quoted text. */ } else { /* Unquoted. white space is bad. */ if (value[in] == TEXT(' ')) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The value of property '%s', '%s' contains unquoted spaces and will most likely result in an invalid java command line."), propName, value); return 1; } } in++; } if (inQuote) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The value of property '%s', '%s' contains an unterminated quote and will most likely result in an invalid java command line."), propName, value); return 1; } return 0; } #ifndef WIN32 int checkIfExecutable(const TCHAR *filename) { int result; #if defined(WIN32) && !defined(WIN64) struct _stat64i32 statInfo; #else struct stat statInfo; #endif result = _tstat(filename, &statInfo); if (result < 0) { return 0; } if (!S_ISREG(statInfo.st_mode)) { return 0; } if (statInfo.st_uid == geteuid()) { return statInfo.st_mode & S_IXUSR; } if (statInfo.st_gid == getegid()) { return statInfo.st_mode & S_IXGRP; } return statInfo.st_mode & S_IXOTH; } #endif int checkIfBinary(const TCHAR *filename) { FILE* f; unsigned char head[5]; int r; f = _tfopen(filename, TEXT("rb")); if (!f) { /*couldnt find the java command... wrapper will moan later*/ return 1; } else { r = (int)fread( head,1, 4, f); if (r != 4) { fclose(f); return 0; } fclose(f); head[4] = '\0'; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Magic number for file %s: 0x%02x%02x%02x%02x"), filename, head[0], head[1], head[2], head[3]); } #if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) if (head[1] == 'E' && head[2] == 'L' && head[3] == 'F') { return 1; /*ELF */ #elif defined(AIX) /* http://en.wikipedia.org/wiki/XCOFF */ if (head[0] == 0x01 && head[1] == 0xf7 && head[2] == 0x00) { /* 0x01f700NN */ return 1; /*xcoff 64*/ } else if (head[0] == 0x01 && head[1] == 0xdf && head[2] == 0x00) { /* 0x01df00NN */ return 1; /*xcoff 32*/ #elif defined(MACOSX) if (head[0] == 0xca && head[1] == 0xfe && head[2] == 0xba && head[3] == 0xbe) { /* 0xcafebabe */ return 1; /*MACOS Universal binary*/ } else if (head[0] == 0xcf && head[1] == 0xfa && head[2] == 0xed && head[3] == 0xfe) { /* 0xcffaedfe */ return 1; /*MACOS x86_64 binary*/ } else if (head[0] == 0xce && head[1] == 0xfa && head[2] == 0xed && head[3] == 0xfe) { /* 0xcefaedfe */ return 1; /*MACOS i386 binary*/ } else if (head[0] == 0xfe && head[1] == 0xed && head[2] == 0xfa && head[3] == 0xce) { /* 0xfeedface */ return 1; /*MACOS ppc, ppc64 binary*/ #elif defined(HPUX) if (head[0] == 0x02 && head[1] == 0x10 && head[2] == 0x01 && head[3] == 0x08) { /* 0x02100108 PA-RISC 1.1 */ return 1; /*HP UX PA RISC 32*/ } else if (head[0] == 0x02 && head[1] == 0x14 && head[2] == 0x01 && head[3] == 0x07) { /* 0x02140107 PA-RISC 2.0 */ return 1; /*HP UX PA RISC 32*/ } else if (head[1] == 'E' && head[2] == 'L' && head[3] == 'F') { return 1; /*ELF */ #elif defined(WIN32) if (head[0] == 'M' && head[1] == 'Z') { return 1; /* MS */ #else if (FALSE) { #error I dont know what to do for this host type. (in checkIfBinary()) #endif } else { return 0; } } } #ifndef WIN32 TCHAR* findPathOf(const TCHAR *exe, const TCHAR *name) { TCHAR *searchPath; TCHAR *beg, *end; int stop, found; TCHAR pth[PATH_MAX + 1]; TCHAR *ret; TCHAR resolvedPath[PATH_MAX + 1]; if (exe[0] == TEXT('/')) { /* This is an absolute reference. */ if (_trealpathN(exe, resolvedPath, PATH_MAX + 1)) { _tcsncpy(pth, resolvedPath, PATH_MAX + 1); if (checkIfExecutable(pth)) { ret = malloc((_tcslen(pth) + 1) * sizeof(TCHAR)); if (!ret) { outOfMemory(TEXT("FPO"), 1); return NULL; } _tcsncpy(ret, pth, _tcslen(pth) + 1); if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Resolved the real path of %s as an absolute reference: %s"), name, ret); } return ret; } } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Unable to resolve the real path of %s as an absolute reference: %s (Problem at: %s)"), name, exe, resolvedPath); } } return NULL; } /* This is a non-absolute reference. See if it is a relative reference. */ if (_trealpathN(exe, resolvedPath, PATH_MAX + 1)) { /* Resolved. See if the file exists. */ _tcsncpy(pth, resolvedPath, PATH_MAX + 1); if (checkIfExecutable(pth)) { ret = malloc((_tcslen(pth) + 1) * sizeof(TCHAR)); if (!ret) { outOfMemory(TEXT("FPO"), 2); return NULL; } _tcsncpy(ret, pth, _tcslen(pth) + 1); if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Resolved the real path of %s as a relative reference: %s"), name, ret); } return ret; } } else { if (wrapperData->isDebugging) { /* Some platforms (MACOSX) will return the point that was the problem, it seems to work * on some other platforms but is documented as undefined. To be safe and keep things * in sync, don't use it. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Unable to resolve the real path of %s as a relative reference: %s"), name, exe); } } /* The file was not a direct relative reference. If and only if it does not contain any relative path components, we can search the PATH. */ if (_tcschr(exe, TEXT('/')) == NULL) { searchPath = _tgetenv(TEXT("PATH")); if (searchPath && (_tcslen(searchPath) <= 0)) { #if !defined(WIN32) && defined(UNICODE) free(searchPath); #endif searchPath = NULL; } if (searchPath) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Attempt to locate %s on system PATH: %s"), name, exe); } beg = searchPath; stop = 0; found = 0; do { end = _tcschr(beg, TEXT(':')); if (end == NULL) { /* This is the last element in the PATH, so we want the whole thing. */ stop = 1; _tcsncpy(pth, beg, PATH_MAX + 1); } else { /* Copy the single path entry. */ _tcsncpy(pth, beg, end - beg); pth[end - beg] = TEXT('\0'); } if (pth[_tcslen(pth) - 1] != TEXT('/')) { _tcsncat(pth, TEXT("/"), PATH_MAX + 1); } _tcsncat(pth, exe, PATH_MAX + 1); /* The file can exist on the path, but via a symbolic link, so we need to expand it. Ignore errors here. */ #ifdef _DEBUG if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" Check PATH entry: %s"), pth); } #endif if (_trealpathN(pth, resolvedPath, PATH_MAX + 1) != NULL) { /* Copy over the result. */ _tcsncpy(pth, resolvedPath, PATH_MAX + 1); found = checkIfExecutable(pth); } if (!stop) { beg = end + 1; } } while (!stop && !found); #if !defined(WIN32) && defined(UNICODE) free(searchPath); #endif if (found) { ret = malloc((_tcslen(pth) + 1) * sizeof(TCHAR)); if (!ret) { outOfMemory(TEXT("FPO"), 3); return NULL; } _tcsncpy(ret, pth, _tcslen(pth) + 1); if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Resolved the real path of %s from system PATH: %s"), name, ret); } return ret; } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Unable to resolve the real path of %s on the system PATH: %s"), name, exe); } } } } /* Still did not find the file. So it must not exist. */ return NULL; } #endif /** * Checks to see if the speicified executable is a regular binary. This will continue * in either case, but a warning will be logged if the binary is invalid. * * @param para The binary to check. On UNIX, the para memory may be freed and reallocated by this call. */ void checkIfRegularExe(TCHAR** para) { TCHAR* path; #ifdef WIN32 int len, start; #endif #ifdef WIN32 if (_tcschr(*para, TEXT('\"')) != NULL){ start = 1; len = (int)_tcslen(*para) - 2; } else { start = 0; len = (int)_tcslen(*para); } path = malloc(sizeof(TCHAR) * (len + 1)); if (!path){ outOfMemory(TEXT("CIRE"), 1); } else { _tcsncpy(path, (*para) + start, len); path[len] = TEXT('\0'); #else int replacePath; path = findPathOf(*para, TEXT("wrapper.java.command")); if (!path) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The configured wrapper.java.command could not be found, attempting to launch anyway: %s"), *para); } else { replacePath = getBooleanProperty(properties, TEXT("wrapper.java.command.resolve"), TRUE); if (replacePath == TRUE) { free(*para); *para = malloc((_tcslen(path) + 1) * sizeof(TCHAR)); if (!(*para)) { outOfMemory(TEXT("CIRE"), 2); free(path); return; } _tcsncpy(*para, path, _tcslen(path) + 1); } #endif if (!checkIfBinary(path)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The value of wrapper.java.command does not appear to be a java binary.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The use of scripts is not supported. Trying to continue, but some features may not work correctly..")); } free(path); } } /** * Builds up the java command section of the Java command line. * * @return The final index into the strings array, or -1 if there were any problems. */ int wrapperBuildJavaCommandArrayJavaCommand(TCHAR **strings, int addQuotes, int detectDebugJVM, int index) { const TCHAR *prop; TCHAR *c; #ifdef WIN32 TCHAR cpPath[512]; int found; #endif if (strings) { prop = getStringProperty(properties, TEXT("wrapper.java.command"), TEXT("java")); #ifdef WIN32 found = 0; if (_tcscmp(prop, TEXT("")) == 0) { /* If the java command is an empty string, we want to look for the * the java command in the windows registry. */ if (wrapperGetJavaHomeFromWindowsRegistry(cpPath)) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Loaded java home from registry: %s"), cpPath); } addProperty(properties, NULL, 0, TEXT("set.WRAPPER_JAVA_HOME"), cpPath, TRUE, FALSE, FALSE, TRUE); _tcsncat(cpPath, TEXT("\\bin\\java.exe"), 512); if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Found Java Runtime Environment home directory in system registry.")); } found = 1; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("The Java Runtime Environment home directory could not be located in the system registry.")); found = 0; return -1; } } else { /* To avoid problems on Windows XP systems, the '/' characters must * be replaced by '\' characters in the specified path. * prop is supposed to be constant, but allow this change as it is * the actual value that we want. */ wrapperCorrectWindowsPath((TCHAR *)prop); /* If the full path to the java command was not specified, then we * need to try and resolve it here to avoid problems later when * calling CreateProcess. CreateProcess will look in the windows * system directory before searching the PATH. This can lead to * the wrong JVM being run. */ _sntprintf(cpPath, 512, TEXT("%s"), prop); if ((PathFindOnPath((TCHAR*)cpPath, (TCHAR**)wrapperGetSystemPath())) && (!PathIsDirectory(cpPath))) { /*printf("Found %s on path.\n", cpPath); */ found = 1; } else { /*printf("Could not find %s on path.\n", cpPath); */ /* Try adding .exe to the end */ _sntprintf(cpPath, 512, TEXT("%s.exe"), prop); if ((PathFindOnPath(cpPath, wrapperGetSystemPath())) && (!PathIsDirectory(cpPath))) { /*printf("Found %s on path.\n", cpPath); */ found = 1; } else { /*printf("Could not find %s on path.\n", cpPath); */ } } } if (found) { strings[index] = malloc(sizeof(TCHAR) * (_tcslen(cpPath) + 2 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAJC"), 1); return -1; } if (addQuotes) { _sntprintf(strings[index], _tcslen(cpPath) + 2 + 1, TEXT("\"%s\""), cpPath); } else { _sntprintf(strings[index], _tcslen(cpPath) + 2 + 1, TEXT("%s"), cpPath); } } else { strings[index] = malloc(sizeof(TCHAR) * (_tcslen(prop) + 2 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAJC"), 2); return -1; } if (addQuotes) { _sntprintf(strings[index], _tcslen(prop) + 2 + 1, TEXT("\"%s\""), prop); } else { _sntprintf(strings[index], _tcslen(prop) + 2 + 1, TEXT("%s"), prop); } } if (addQuotes) { wrapperCheckQuotes(strings[index], TEXT("wrapper.java.command")); } #else /* UNIX */ strings[index] = malloc(sizeof(TCHAR) * (_tcslen(prop) + 2 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAJC"), 3); return -1; } if (addQuotes) { _sntprintf(strings[index], _tcslen(prop) + 2 + 1, TEXT("\"%s\""), prop); } else { _sntprintf(strings[index], _tcslen(prop) + 2 + 1, TEXT("%s"), prop); } #endif checkIfRegularExe(&strings[index]); if (detectDebugJVM) { c = _tcsstr(strings[index], TEXT("jdb")); if (c && ((unsigned int)(c - strings[index]) == _tcslen(strings[index]) - 3 - 1)) { /* Ends with "jdb". The jdb debugger is being used directly. go into debug JVM mode. */ wrapperData->debugJVM = TRUE; } else { c = _tcsstr(strings[index], TEXT("jdb.exe")); if (c && ((unsigned int)(c - strings[index]) == _tcslen(strings[index]) - 7 - 1)) { /* Ends with "jdb". The jdb debugger is being used directly. go into debug JVM mode. */ wrapperData->debugJVM = TRUE; } } } } index++; return index; } /** * Builds up the additional section of the Java command line. * * @return The final index into the strings array, or -1 if there were any problems. */ int wrapperBuildJavaCommandArrayJavaAdditional(TCHAR **strings, int addQuotes, int detectDebugJVM, int index) { const TCHAR *prop; int i; size_t len; TCHAR paramBuffer2[128]; int quotable; int defaultStripQuote; int stripQuote; TCHAR *propStripped; TCHAR **propertyNames; TCHAR **propertyValues; long unsigned int *propertyIndices; if (getStringProperties(properties, TEXT("wrapper.java.additional."), TEXT(""), wrapperData->ignoreSequenceGaps, FALSE, &propertyNames, &propertyValues, &propertyIndices)) { /* Failed */ return -1; } defaultStripQuote = getBooleanProperty(properties, TEXT("wrapper.java.additional.default.stripquotes"), FALSE); i = 0; while (propertyNames[i]) { prop = propertyValues[i]; if (prop) { if (_tcslen(prop) > 0) { /* All additional parameters must begin with a - or they will be interpretted * as the being the main class name by Java. */ if (!((_tcsstr(prop, TEXT("-")) == prop) || (_tcsstr(prop, TEXT("\"-")) == prop))) { /* Only log the message on the second pass. */ if (strings) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The value of property '%s', '%s' is not a valid argument to the JVM. Skipping."), propertyNames[i], prop); } } else { if (strings) { /* is quotable also changes the value of the property! therefore prop can potentially point to free'd memory*/ quotable = isQuotableProperty(properties, propertyNames[i]); prop = getStringProperty(properties, propertyNames[i], NULL); propertyValues[i] = (TCHAR*) prop; if (prop == NULL) { freeStringProperties(propertyNames, propertyValues, propertyIndices); return -1; } _sntprintf(paramBuffer2, 128, TEXT("wrapper.java.additional.%lu.stripquotes"), propertyIndices[i]); if (addQuotes) { stripQuote = FALSE; } else { stripQuote = getBooleanProperty(properties, paramBuffer2, defaultStripQuote); } if (stripQuote) { propStripped = malloc(sizeof(TCHAR) * (_tcslen(prop) + 1)); if (!propStripped) { freeStringProperties(propertyNames, propertyValues, propertyIndices); outOfMemory(TEXT("WBJCAJA"), 2); return -1; } wrapperStripQuotes(prop, propStripped); } else { propStripped = (TCHAR *)prop; } if (addQuotes && quotable && _tcschr(propStripped, TEXT(' '))) { len = wrapperQuoteValue(propStripped, NULL, 0); strings[index] = malloc(sizeof(TCHAR) * len); if (!strings[index]) { outOfMemory(TEXT("WBJCAJA"), 3); freeStringProperties(propertyNames, propertyValues, propertyIndices); if (stripQuote) { free(propStripped); } return -1; } wrapperQuoteValue(propStripped, strings[index], len); } else { strings[index] = malloc(sizeof(TCHAR) * (_tcslen(propStripped) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAJA"), 4); freeStringProperties(propertyNames, propertyValues, propertyIndices); if (stripQuote) { free(propStripped); } return -1; } _sntprintf(strings[index], _tcslen(propStripped) + 1, TEXT("%s"), propStripped); } if (addQuotes) { wrapperCheckQuotes(strings[index], propertyNames[i]); } if (stripQuote) { free(propStripped); propStripped = NULL; } /* Set if this paremeter enables debugging. */ if (detectDebugJVM) { if (_tcsstr(strings[index], TEXT("-Xdebug")) == strings[index]) { wrapperData->debugJVM = TRUE; } } } index++; } } i++; } } freeStringProperties(propertyNames, propertyValues, propertyIndices); return index; } /** * Java command line callback. * * @return FALSE if there were any problems. */ static int loadParameterFileCallbackParam_AddArg(LoadParameterFileCallbackParam *param, TCHAR *arg, size_t argLen) { TCHAR *argTerm; TCHAR *argStripped; TCHAR argExpanded[MAX_PROPERTY_VALUE_LENGTH]; size_t len; /* The incoming arg can not be considered to be null terminated so we need a local copy. */ if (!(argTerm = malloc(sizeof(TCHAR) * (argLen + 1)))) { outOfMemory(TEXT("LPFCPAA"), 1); return FALSE; } memcpy(argTerm, arg, sizeof(TCHAR) * argLen); argTerm[argLen] = TEXT('\0'); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_NOTICE, TEXT(" :> %s"), argTerm); #endif if (param->isJVMParam == TRUE) { /* As in wrapperBuildJavaCommandArrayJavaAdditional(), skip an argument which does not begin with '-'. */ if ((argTerm[0] != TEXT('-')) && !((argTerm[0] == TEXT('"')) && (argTerm[1] == TEXT('-')))) { if (param->strings) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The value '%s' is not a valid argument to the JVM. Skipping."), argTerm); } free(argTerm); return TRUE; } } if (param->strings) { /* Create a buffer to hold the stripped copy of argTerm. */ len = _tcslen(argTerm); if (!(argStripped = malloc(sizeof(TCHAR) * (len + 1)))) { outOfMemory(TEXT("LPFCPAA"), 2); free(argTerm); return FALSE; } if (!param->stripQuote) { /* Nothing to strip, simply copy the string. */ _tcsncpy(argStripped, argTerm, len + 1); } else { /* Strip the quotes. */ wrapperStripQuotes(argTerm, argStripped); } /* No longer needed. */ free(argTerm); /* Just in case the string contains and environment variable references, make sure they are all evaluated. * argExpanded needs to be static because there is no way to know how long it will be in advance. */ evaluateEnvironmentVariables(argStripped, argExpanded, MAX_PROPERTY_VALUE_LENGTH, properties->logWarnings, properties->warnedVarMap, properties->logWarningLogLevel); /* No longer needed. */ free(argStripped); len = _tcslen(argExpanded); param->strings[param->index] = malloc(sizeof(TCHAR) * (len + 1)); if (!param->strings[param->index]) { return FALSE; } _tcsncpy(param->strings[param->index], argExpanded, len + 1); } else { free(argTerm); } param->index++; return TRUE; } static int loadParameterFileCallback(void *callbackParam, const TCHAR *fileName, int lineNumber, TCHAR *config, int debugProperties) { LoadParameterFileCallbackParam *param = (LoadParameterFileCallbackParam *)callbackParam; TCHAR *tail_bound; TCHAR *arg; TCHAR *s; int InDelim = FALSE; int InQuotes = FALSE; int Escaped = FALSE; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_NOTICE, TEXT(" : %s"), config); #endif /* Assume that the line `config' has no white spaces at its beginning and end. */ assert(config && _tcslen(config) > 0); assert(config[0] != TEXT(' ') && config[_tcslen(config) - 1] != TEXT(' ')); tail_bound = config + _tcslen(config) + 1; for (arg = s = config; s < tail_bound; s++) { switch (*s) { case TEXT('\0'): if (!loadParameterFileCallbackParam_AddArg(param, arg, s - arg)) { outOfMemory(TEXT("LJAC"), 1); return FALSE; } break; case TEXT(' '): Escaped = FALSE; if (!InDelim && !InQuotes) { InDelim = TRUE; if (!loadParameterFileCallbackParam_AddArg(param, arg, s - arg)) { outOfMemory(TEXT("LJAC"), 2); return FALSE; } } break; case TEXT('"'): if (!Escaped) { InQuotes = !InQuotes; } Escaped = FALSE; if (InDelim) { InDelim = FALSE; arg = s; } break; case TEXT('\\'): Escaped = !Escaped; if (InDelim) { InDelim = FALSE; arg = s; } break; default: Escaped = FALSE; if (InDelim) { InDelim = FALSE; arg = s; } break; } } return TRUE; } /** * Builds up the additional section of the Java command line. * * @return The final index into the strings array, or -1 if there were any problems. */ int wrapperLoadParameterFile(TCHAR **strings, int addQuotes, int detectDebugJVM, int index, TCHAR *parameterName, int isJVMParameter) { const TCHAR *parameterFilePath; LoadParameterFileCallbackParam callbackParam; int readResult; TCHAR prop[256]; parameterFilePath = getFileSafeStringProperty(properties, parameterName, TEXT("")); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_NOTICE, TEXT("%s=%s"), parameterName, parameterFilePath ? parameterFilePath : TEXT("")); #endif if (_tcslen(parameterFilePath) == 0) { return index; } if (addQuotes) { callbackParam.stripQuote = FALSE; } else { _sntprintf(prop, 256, TEXT("%s.stripquotes"), parameterName); callbackParam.stripQuote = getBooleanProperty(properties, prop, FALSE); } callbackParam.strings = strings; callbackParam.index = index; callbackParam.isJVMParam = isJVMParameter; readResult = configFileReader(parameterFilePath, TRUE, loadParameterFileCallback, &callbackParam, FALSE, FALSE, wrapperData->argCommand, wrapperData->originalWorkingDir, properties->warnedVarMap, properties->logWarnings, properties->logWarningLogLevel, wrapperData->isDebugging); switch (readResult) { case CONFIG_FILE_READER_SUCCESS: return callbackParam.index; case CONFIG_FILE_READER_FAIL: case CONFIG_FILE_READER_HARD_FAIL: return -1; default: _tprintf(TEXT("Unexpected read error %d\n"), readResult); return index; }; } /** * Builds up the library path section of the Java command line. * * @return The final index into the strings array, or -1 if there were any problems. */ int wrapperBuildJavaCommandArrayLibraryPath(TCHAR **strings, int addQuotes, int index) { const TCHAR *prop; int i, j; size_t len2; size_t cpLen, cpLenAlloc; TCHAR *tmpString; TCHAR *systemPath; TCHAR **propertyNames; TCHAR **propertyValues; long unsigned int *propertyIndices; if (strings) { if (wrapperData->libraryPathAppendPath) { /* We are going to want to append the full system path to * whatever library path is generated. */ #ifdef WIN32 systemPath = _tgetenv(TEXT("PATH")); #else systemPath = _tgetenv(TEXT("LD_LIBRARY_PATH")); #endif if (systemPath) { /* If we are going to add our own quotes then we need to make sure that the system * PATH doesn't contain any of its own. Windows allows users to do this... */ if (addQuotes) { i = 0; j = 0; do { if (systemPath[i] != TEXT('"') ) { systemPath[j] = systemPath[i]; j++; } i++; } while (systemPath[j] != TEXT('\0')); } } } else { systemPath = NULL; } prop = getStringProperty(properties, TEXT("wrapper.java.library.path"), NULL); if (prop) { /* An old style library path was specified. * If quotes are being added, check the last character before the * closing quote. If it is a backslash then Windows will use it to * escape the quote. To make things work correctly, we need to add * another backslash first so it will result in a single backslash * before the quote. */ if (systemPath) { strings[index] = malloc(sizeof(TCHAR) * (22 + _tcslen(prop) + 1 + _tcslen(systemPath) + 1 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCALP"), 1); #if !defined(WIN32) && defined(UNICODE) free(systemPath); #endif return -1; } if (addQuotes) { if ((_tcslen(systemPath) > 1) && (systemPath[_tcslen(systemPath) - 1] == TEXT('\\'))) { _sntprintf(strings[index], 22 + _tcslen(prop) + 1 + _tcslen(systemPath) + 1 + 1, TEXT("-Djava.library.path=\"%s%c%s\\\""), prop, wrapperClasspathSeparator, systemPath); } else { _sntprintf(strings[index], 22 + _tcslen(prop) + 1 + _tcslen(systemPath) + 1 + 1, TEXT("-Djava.library.path=\"%s%c%s\""), prop, wrapperClasspathSeparator, systemPath); } } else { _sntprintf(strings[index], 22 + _tcslen(prop) + 1 + _tcslen(systemPath) + 1 + 1, TEXT("-Djava.library.path=%s%c%s"), prop, wrapperClasspathSeparator, systemPath); } } else { strings[index] = malloc(sizeof(TCHAR) * (22 + _tcslen(prop) + 1 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCALP"), 2); return -1; } if (addQuotes) { if ((_tcslen(prop) > 1) && (prop[_tcslen(prop) - 1] == TEXT('\\'))) { _sntprintf(strings[index], 22 + _tcslen(prop) + 1 + 1, TEXT("-Djava.library.path=\"%s\\\""), prop); } else { _sntprintf(strings[index], 22 + _tcslen(prop) + 1 + 1, TEXT("-Djava.library.path=\"%s\""), prop); } } else { _sntprintf(strings[index], 22 + _tcslen(prop) + 1 + 1, TEXT("-Djava.library.path=%s"), prop); } } if (addQuotes) { wrapperCheckQuotes(strings[index], TEXT("wrapper.java.library.path")); } } else { /* Look for a multiline library path. */ cpLen = 0; cpLenAlloc = 1024; strings[index] = malloc(sizeof(TCHAR) * cpLenAlloc); if (!strings[index]) { outOfMemory(TEXT("WBJCALP"), 3); #if !defined(WIN32) && defined(UNICODE) if (systemPath) { free(systemPath); } #endif return -1; } /* Start with the property value. */ _sntprintf(&(strings[index][cpLen]), cpLenAlloc - cpLen, TEXT("-Djava.library.path=")); cpLen += 20; /* Add an open quote to the library path */ if (addQuotes) { _sntprintf(&(strings[index][cpLen]), cpLenAlloc - cpLen, TEXT("\"")); cpLen++; } /* Loop over the library path entries adding each one */ if (getStringProperties(properties, TEXT("wrapper.java.library.path."), TEXT(""), wrapperData->ignoreSequenceGaps, FALSE, &propertyNames, &propertyValues, &propertyIndices)) { /* Failed */ #if !defined(WIN32) && defined(UNICODE) if (systemPath) { free(systemPath); } #endif return -1; } i = 0; j = 0; while (propertyNames[i]) { prop = propertyValues[i]; if (prop) { len2 = _tcslen(prop); if (len2 > 0) { /* Is there room for the entry? */ while (cpLen + len2 + 3 > cpLenAlloc) { /* Resize the buffer */ tmpString = strings[index]; cpLenAlloc += 1024; strings[index] = malloc(sizeof(TCHAR) * cpLenAlloc); if (!strings[index]) { outOfMemory(TEXT("WBJCALP"), 4); #if !defined(WIN32) && defined(UNICODE) if (systemPath) { free(systemPath); } #endif return -1; } _sntprintf(strings[index], cpLenAlloc, TEXT("%s"), tmpString); free(tmpString); tmpString = NULL; } if (j > 0) { strings[index][cpLen++] = wrapperClasspathSeparator; /* separator */ } _sntprintf(&(strings[index][cpLen]), cpLenAlloc - cpLen, TEXT("%s"), prop); cpLen += len2; j++; } i++; } } freeStringProperties(propertyNames, propertyValues, propertyIndices); if (systemPath) { /* We need to append the system path. */ len2 = _tcslen(systemPath); if (len2 > 0) { /* Is there room for the entry? */ while (cpLen + len2 + 3 > cpLenAlloc) { /* Resize the buffer */ tmpString = strings[index]; cpLenAlloc += 1024; strings[index] = malloc(sizeof(TCHAR) * cpLenAlloc); if (!strings[index]) { outOfMemory(TEXT("WBJCALP"), 5); #if !defined(WIN32) && defined(UNICODE) free(systemPath); #endif return -1; } _sntprintf(strings[index], cpLenAlloc, TEXT("%s"), tmpString); free(tmpString); tmpString = NULL; } if (j > 0) { strings[index][cpLen++] = wrapperClasspathSeparator; /* separator */ } _sntprintf(&(strings[index][cpLen]), cpLenAlloc - cpLen, TEXT("%s"), systemPath); cpLen += len2; j++; } } if (j == 0) { /* No library path, use default. always room */ _sntprintf(&(strings[index][cpLen]), cpLenAlloc - cpLen, TEXT("./")); cpLen++; } /* Add ending quote. If the previous character is a backslash then * Windows will use it to escape the quote. To make things work * correctly, we need to add another backslash first so it will * result in a single backslash before the quote. */ if (addQuotes) { if (strings[index][cpLen - 1] == TEXT('\\')) { _sntprintf(&(strings[index][cpLen]), cpLenAlloc - cpLen, TEXT("\\")); cpLen++; } _sntprintf(&(strings[index][cpLen]), cpLenAlloc - cpLen, TEXT("\"")); cpLen++; } if (addQuotes) { wrapperCheckQuotes(strings[index], TEXT("wrapper.java.library.path.")); } } #if !defined(WIN32) && defined(UNICODE) if (systemPath) { free(systemPath); } #endif } index++; return index; } /** * Builds up the java classpath. * * @return 0 if successful, or -1 if there were any problems. */ int wrapperBuildJavaClasspath(TCHAR **classpath) { const TCHAR *prop; TCHAR *propStripped; TCHAR *propBaseDir; int i, j; size_t cpLen, cpLenAlloc; size_t len2; TCHAR *tmpString; #if defined(WIN32) && !defined(WIN64) struct _stat64i32 statBuffer; #else struct stat statBuffer; #endif TCHAR **propertyNames; TCHAR **propertyValues; long unsigned int *propertyIndices; TCHAR **files; int cnt; int missingLogLevel; /* Build a classpath */ cpLen = 0; cpLenAlloc = 1024; *classpath = malloc(sizeof(TCHAR) * cpLenAlloc); if (!*classpath) { outOfMemory(TEXT("WBJCP"), 1); return -1; } /* Loop over the classpath entries adding each one. */ if (getStringProperties(properties, TEXT("wrapper.java.classpath."), TEXT(""), wrapperData->ignoreSequenceGaps, FALSE, &propertyNames, &propertyValues, &propertyIndices)) { /* Failed */ return -1; } /* Get the loglevel to display warnings about missing classpath elements. */ missingLogLevel = getLogLevelForName(getStringProperty(properties, TEXT("wrapper.java.classpath.missing.loglevel"), TEXT("DEBUG"))); i = 0; j = 0; while (propertyNames[i]) { prop = propertyValues[i]; /* Does this contain any quotes? */ if (_tcschr(prop, TEXT('"'))) { propStripped = malloc(sizeof(TCHAR) * (_tcslen(prop) + 1)); if (!propStripped) { outOfMemory(TEXT("WBJCP"), 2); freeStringProperties(propertyNames, propertyValues, propertyIndices); return -1; } wrapperStripQuotes(prop, propStripped); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT( "Classpath element, %s, should not contain quotes: %s, stripping and continuing: %s"), propertyNames[i], prop, propStripped); } else { propStripped = (TCHAR *)prop; } len2 = _tcslen(propStripped); if (len2 > 0) { /* Does this contain wildcards? */ if ((_tcsrchr(propStripped, TEXT('*')) != NULL) || (_tcschr(propStripped, TEXT('?')) != NULL)) { /* Need to do a wildcard search */ files = loggerFileGetFiles(propStripped, LOGGER_FILE_SORT_MODE_NAMES_ASC); if (!files) { /* Failed */ if (propStripped != prop) { free(propStripped); } freeStringProperties(propertyNames, propertyValues, propertyIndices); return -1; } /* Loop over the files. */ cnt = 0; while (files[cnt]) { len2 = _tcslen(files[cnt]); /* Is there room for the entry? */ if (cpLen + len2 + 3 > cpLenAlloc) { /* Resize the buffer */ tmpString = *classpath; cpLenAlloc += len2 + 3; *classpath = malloc(sizeof(TCHAR) * cpLenAlloc); if (!*classpath) { if (propStripped != prop) { free(propStripped); } loggerFileFreeFiles(files); freeStringProperties(propertyNames, propertyValues, propertyIndices); outOfMemory(TEXT("WBJCP"), 2); return -1; } if (j > 0) { _sntprintf(*classpath, cpLenAlloc, TEXT("%s"), tmpString); } free(tmpString); tmpString = NULL; } if (j > 0) { (*classpath)[cpLen++] = wrapperClasspathSeparator; /* separator */ } _sntprintf(&((*classpath)[cpLen]), cpLenAlloc - cpLen, TEXT("%s"), files[cnt]); cpLen += len2; j++; cnt++; } loggerFileFreeFiles(files); } else { /* This classpath entry does not contain any wildcards. */ /* If the path element is a directory then we want to strip the trailing slash if it exists. */ propBaseDir = (TCHAR*)propStripped; if ((propStripped[_tcslen(propStripped) - 1] == TEXT('/')) || (propStripped[_tcslen(propStripped) - 1] == TEXT('\\'))) { propBaseDir = malloc(sizeof(TCHAR) * _tcslen(propStripped)); if (!propBaseDir) { outOfMemory(TEXT("WBJCP"), 3); if (propStripped != prop) { free(propStripped); } freeStringProperties(propertyNames, propertyValues, propertyIndices); return -1; } _tcsncpy(propBaseDir, propStripped, _tcslen(propStripped) - 1); propBaseDir[_tcslen(propStripped) - 1] = TEXT('\0'); } /* See if it exists so we can display a debug warning if it does not. */ if (_tstat(propBaseDir, &statBuffer)) { /* Encountered an error of some kind. */ if ((errno == ENOENT) || (errno == 3)) { log_printf(WRAPPER_SOURCE_WRAPPER, missingLogLevel, TEXT( "Classpath element, %s, does not exist: %s"), propertyNames[i], propStripped); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Unable to get information of classpath element: %s (%s)"), propStripped, getLastErrorText()); } } else { /* Got the stat info. */ } /* If we allocated the propBaseDir buffer then free it up. */ if (propBaseDir != propStripped) { free(propBaseDir); } propBaseDir = NULL; /* Is there room for the entry? */ if (cpLen + len2 + 3 > cpLenAlloc) { /* Resize the buffer */ tmpString = *classpath; cpLenAlloc += len2 + 3; *classpath = malloc(sizeof(TCHAR) * cpLenAlloc); if (!*classpath) { outOfMemory(TEXT("WBJCP"), 4); if (propStripped != prop) { free(propStripped); } freeStringProperties(propertyNames, propertyValues, propertyIndices); return -1; } if (j > 0) { _sntprintf(*classpath, cpLenAlloc, TEXT("%s"), tmpString); } free(tmpString); tmpString = NULL; } if (j > 0) { (*classpath)[cpLen++] = wrapperClasspathSeparator; /* separator */ } _sntprintf(&((*classpath)[cpLen]), cpLenAlloc - cpLen, TEXT("%s"), propStripped); cpLen += len2; j++; } } /* If we allocated the propStripped buffer then free it up. */ if (propStripped != prop) { free(propStripped); } propStripped = NULL; i++; } freeStringProperties(propertyNames, propertyValues, propertyIndices); if (j == 0) { /* No classpath, use default. always room */ _sntprintf(&(*classpath[cpLen]), cpLenAlloc - cpLen, TEXT("./")); cpLen++; } return 0; } /** * Builds up the java classpath section of the Java command line. * * @return The final index into the strings array, or -1 if there were any problems. */ int wrapperBuildJavaCommandArrayClasspath(TCHAR **strings, int addQuotes, int index, const TCHAR *classpath) { size_t len; size_t cpLen; /* Store the classpath */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (10 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAC"), 1); return -1; } _sntprintf(strings[index], 10 + 1, TEXT("-classpath")); } index++; if (strings) { cpLen = 0; len = _tcslen(classpath); strings[index] = malloc(sizeof(TCHAR) * (len + 4)); if (!strings[index]) { outOfMemory(TEXT("WBJCAC"), 2); return -1; } /* Add an open quote the classpath */ if (addQuotes) { _sntprintf(&(strings[index][cpLen]), len + 4 - cpLen, TEXT("\"")); cpLen++; } _sntprintf(&(strings[index][cpLen]), len + 4 - cpLen, TEXT("%s"), classpath); cpLen += len; /* Add ending quote. If the previous character is a backslash then * Windows will use it to escape the quote. To make things work * correctly, we need to add another backslash first so it will * result in a single backslash before the quote. */ if (addQuotes) { if (strings[index][cpLen - 1] == TEXT('\\')) { _sntprintf(&(strings[index][cpLen]), len + 4 - cpLen, TEXT("\\")); cpLen++; } _sntprintf(&(strings[index][cpLen]), len + 4 - cpLen, TEXT("\"")); cpLen++; } if (addQuotes) { wrapperCheckQuotes(strings[index], TEXT("wrapper.java.classpath.")); } } index++; return index; } /** * Builds up the app parameters section of the Java command line. * * @return The final index into the strings array, or -1 if there were any problems. */ int wrapperBuildJavaCommandArrayAppParameters(TCHAR **strings, int addQuotes, int index, int thisIsTestWrapper) { const TCHAR *prop; int i; int quotable; TCHAR *propStripped; int defaultStripQuote; int stripQuote; TCHAR paramBuffer2[128]; size_t len; TCHAR **propertyNames; TCHAR **propertyValues; long unsigned int *propertyIndices; if (getStringProperties(properties, TEXT("wrapper.app.parameter."), TEXT(""), wrapperData->ignoreSequenceGaps, FALSE, &propertyNames, &propertyValues, &propertyIndices)) { /* Failed */ return -1; } defaultStripQuote = getBooleanProperty(properties, TEXT("wrapper.app.parameter.default.stripquotes"), FALSE); i = 0; while (propertyNames[i]) { prop = propertyValues[i]; if (_tcslen(prop) > 0) { if (thisIsTestWrapper && (i == 1) && ((_tcscmp(prop, TEXT("{{TestWrapperBat}}")) == 0) || (_tcscmp(prop, TEXT("{{TestWrapperSh}}")) == 0))) { /* This is the TestWrapper dummy parameter. Simply skip over it so it doesn't get put into the command line. */ } else { if (strings) { quotable = isQuotableProperty(properties, propertyNames[i]); _sntprintf(paramBuffer2, 128, TEXT("wrapper.app.parameter.%lu.stripquotes"), propertyIndices[i]); if (addQuotes) { stripQuote = FALSE; } else { stripQuote = getBooleanProperty(properties, paramBuffer2, defaultStripQuote); } if (stripQuote) { propStripped = malloc(sizeof(TCHAR) * (_tcslen(prop) + 1)); if (!propStripped) { outOfMemory(TEXT("WBJCAAP"), 1); freeStringProperties(propertyNames, propertyValues, propertyIndices); return -1; } wrapperStripQuotes(prop, propStripped); } else { propStripped = (TCHAR *)prop; } if (addQuotes && quotable && _tcschr(propStripped, TEXT(' '))) { len = wrapperQuoteValue(propStripped, NULL, 0); strings[index] = malloc(sizeof(TCHAR) * len); if (!strings[index]) { outOfMemory(TEXT("WBJCAAP"), 2); if (stripQuote) { free(propStripped); } freeStringProperties(propertyNames, propertyValues, propertyIndices); return -1; } wrapperQuoteValue(propStripped, strings[index], len); } else { strings[index] = malloc(sizeof(TCHAR) * (_tcslen(propStripped) + 1)); if (!strings[index]) { if (stripQuote) { free(propStripped); } freeStringProperties(propertyNames, propertyValues, propertyIndices); outOfMemory(TEXT("WBJCAAP"), 3); return -1; } _sntprintf(strings[index], _tcslen(propStripped) + 1, TEXT("%s"), propStripped); } if (addQuotes) { wrapperCheckQuotes(strings[index], propertyNames[i]); } if (stripQuote) { free(propStripped); propStripped = NULL; } } index++; } } i++; } freeStringProperties(propertyNames, propertyValues, propertyIndices); /* precede command line parameters */ if (wrapperData->javaArgValueCount > 0) { for (i = 0; i < wrapperData->javaArgValueCount; i++) { if (strings) { if (addQuotes && _tcschr(wrapperData->javaArgValues[i], TEXT(' '))) { len = wrapperQuoteValue(wrapperData->javaArgValues[i], NULL, 0); strings[index] = malloc(sizeof(TCHAR) * len); if (!strings[index]) { outOfMemory(TEXT("WBJCAAP"), 4); return -1; } wrapperQuoteValue(wrapperData->javaArgValues[i], strings[index], len); } else { strings[index] = malloc(sizeof(TCHAR) * (_tcslen(wrapperData->javaArgValues[i]) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAAP"), 5); return -1; } _sntprintf(strings[index], _tcslen(wrapperData->javaArgValues[i]) + 1, TEXT("%s"), wrapperData->javaArgValues[i]); } } index++; } } return index; } /** * Loops over and stores all necessary commands into an array which * can be used to launch a process. * This method will only count the elements if stringsPtr is NULL. * * Note - Next Out Of Memory is #47 * * @return The final index into the strings array, or -1 if there were any problems. */ int wrapperBuildJavaCommandArrayInner(TCHAR **strings, int addQuotes, const TCHAR *classpath) { int index; int detectDebugJVM; const TCHAR *prop; int initMemory = 0; int maxMemory; int thisIsTestWrapper; setLogPropertyWarnings(properties, strings != NULL); index = 0; detectDebugJVM = getBooleanProperty(properties, TEXT("wrapper.java.detect_debug_jvm"), TRUE); /* Java commnd */ if ((index = wrapperBuildJavaCommandArrayJavaCommand(strings, addQuotes, detectDebugJVM, index)) < 0) { return -1; } /* See if the auto bits parameter is set. Ignored by all but the following platforms. */ #if /*defined(WIN32) || defined(LINUX) ||*/ defined(HPUX) || defined(MACOSX) || defined(SOLARIS) || defined(FREEBSD) if (getBooleanProperty(properties, /*#ifdef WIN32 TEXT("wrapper.java.additional.auto_bits.windows"), #elif defined(LINUX) TEXT("wrapper.java.additional.auto_bits.linux"), */ #if defined(HPUX) TEXT("wrapper.java.additional.auto_bits.hpux"), #elif defined(SOLARIS) TEXT("wrapper.java.additional.auto_bits.solaris"), #elif defined(FREEBSD) TEXT("wrapper.java.additional.auto_bits.freebsd"), #elif defined(MACOSX) TEXT("wrapper.java.additional.auto_bits.macosx"), #endif getBooleanProperty(properties, TEXT("wrapper.java.additional.auto_bits"), FALSE))) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * 5); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 46); return -1; } _sntprintf(strings[index], 5, TEXT("-d%s"), wrapperBits); } index++; } #endif /* Store additional java parameters */ if ((index = wrapperBuildJavaCommandArrayJavaAdditional(strings, addQuotes, detectDebugJVM, index)) < 0) { return -1; } /* Store additional java parameters specified in the parameter file */ if ((index = wrapperLoadParameterFile(strings, addQuotes, detectDebugJVM, index, TEXT("wrapper.java.additional_file"), TRUE)) < 0) { return -1; } /* Initial JVM memory */ initMemory = getIntProperty(properties, TEXT("wrapper.java.initmemory"), 0); if (initMemory > 0) { if (strings) { initMemory = __max(initMemory, 1); /* 1 <= n */ strings[index] = malloc(sizeof(TCHAR) * (5 + 10 + 1)); /* Allow up to 10 digits. */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 8); return -1; } _sntprintf(strings[index], 5 + 10 + 1, TEXT("-Xms%dm"), initMemory); } index++; } else { /* Set the initMemory so the checks in the maxMemory section below will work correctly. */ initMemory = 3; } /* Maximum JVM memory */ maxMemory = getIntProperty(properties, TEXT("wrapper.java.maxmemory"), 0); if (maxMemory > 0) { if (strings) { maxMemory = __max(maxMemory, initMemory); /* initMemory <= n */ strings[index] = malloc(sizeof(TCHAR) * (5 + 10 + 1)); /* Allow up to 10 digits. */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 10); return -1; } _sntprintf(strings[index], 5 + 10 + 1, TEXT("-Xmx%dm"), maxMemory); } index++; } /* Library Path */ if ((index = wrapperBuildJavaCommandArrayLibraryPath(strings, addQuotes, index)) < 0) { return -1; } /* Classpath */ if (!wrapperData->environmentClasspath) { if ((index = wrapperBuildJavaCommandArrayClasspath(strings, addQuotes, index, classpath)) < 0) { return -1; } } /* Store the Wrapper key */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (16 + _tcslen(wrapperData->key) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 24); return -1; } if (addQuotes) { _sntprintf(strings[index], 16 + _tcslen(wrapperData->key) + 1, TEXT("-Dwrapper.key=\"%s\""), wrapperData->key); } else { _sntprintf(strings[index], 16 + _tcslen(wrapperData->key) + 1, TEXT("-Dwrapper.key=%s"), wrapperData->key); } } index++; /* Store the backend connection information. */ if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_PIPE) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (22 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 25); return -1; } _sntprintf(strings[index], 22 + 1, TEXT("-Dwrapper.backend=pipe")); } index++; } else { /* default is socket ipv4, so we have to specify ipv6 if it's the case */ if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_SOCKET_V6) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (29 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 261); return -1; } _sntprintf(strings[index], 29 + 1, TEXT("-Dwrapper.backend=socket_ipv6")); } index++; /* specify to the JVM to change the preference and use IPv6 addresses over IPv4 ones where possible. */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (35 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 262); return -1; } _sntprintf(strings[index], 35 + 1, TEXT("-Djava.net.preferIPv6Addresses=TRUE")); } index++; } /* Store the Wrapper server port */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (15 + 5 + 1)); /* Port up to 5 characters */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 26); return -1; } _sntprintf(strings[index], 15 + 5 + 1, TEXT("-Dwrapper.port=%d"), (int)wrapperData->actualPort); } index++; } /* Store the Wrapper jvm min and max ports. */ if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_SOCKET) { if (wrapperData->portAddress != NULL) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (_tcslen(TEXT("-Dwrapper.port.address=")) + _tcslen(wrapperData->portAddress) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 27); return -1; } _sntprintf(strings[index], _tcslen(TEXT("-Dwrapper.port.address=")) + _tcslen(wrapperData->portAddress) + 1, TEXT("-Dwrapper.port.address=%s"), wrapperData->portAddress); } index++; } if (wrapperData->jvmPort >= 0) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (19 + 5 + 1)); /* Port up to 5 characters */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 28); return -1; } _sntprintf(strings[index], 19 + 5 + 1, TEXT("-Dwrapper.jvm.port=%d"), (int)wrapperData->jvmPort); } index++; } if (strings) { strings[index] = malloc(sizeof(TCHAR) * (23 + 5 + 1)); /* Port up to 5 characters */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 29); return -1; } _sntprintf(strings[index], 23 + 5 + 1, TEXT("-Dwrapper.jvm.port.min=%d"), (int)wrapperData->jvmPortMin); } index++; if (strings) { strings[index] = malloc(sizeof(TCHAR) * (23 + 5 + 1)); /* Port up to 5 characters */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 30); return -1; } _sntprintf(strings[index], 23 + 5 + 1, TEXT("-Dwrapper.jvm.port.max=%d"), (int)wrapperData->jvmPortMax); } index++; } /* Store the Wrapper debug flag */ if (wrapperData->isDebugging) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (22 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 31); return -1; } if (addQuotes) { _sntprintf(strings[index], 22 + 1, TEXT("-Dwrapper.debug=\"TRUE\"")); } else { _sntprintf(strings[index], 22 + 1, TEXT("-Dwrapper.debug=TRUE")); } } index++; } /* Store the Wrapper disable console input flag. */ if (getBooleanProperty(properties, TEXT("wrapper.disable_console_input"), #ifdef WIN32 FALSE #else wrapperData->daemonize /* We want to disable console input by default when daemonized. */ #endif )) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (38 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 32); return -1; } if (addQuotes) { _sntprintf(strings[index], 38 + 1, TEXT("-Dwrapper.disable_console_input=\"TRUE\"")); } else { _sntprintf(strings[index], 38 + 1, TEXT("-Dwrapper.disable_console_input=TRUE")); } } index++; } /* Store the Wrapper listener force stop flag. */ if (getBooleanProperty(properties, TEXT("wrapper.listener.force_stop"), FALSE)) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (38 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 33); return -1; } if (addQuotes) { _sntprintf(strings[index], 38 + 1, TEXT("-Dwrapper.listener.force_stop=\"TRUE\"")); } else { _sntprintf(strings[index], 38 + 1, TEXT("-Dwrapper.listener.force_stop=TRUE")); } } index++; } /* Store the Wrapper PID */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (24 + 1)); /* Pid up to 10 characters */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 34); return -1; } #if defined(SOLARIS) && (!defined(_LP64)) _sntprintf(strings[index], 24 + 1, TEXT("-Dwrapper.pid=%ld"), wrapperData->wrapperPID); #else _sntprintf(strings[index], 24 + 1, TEXT("-Dwrapper.pid=%d"), wrapperData->wrapperPID); #endif } index++; /* Store a flag telling the JVM to use the system clock. */ if (wrapperData->useSystemTime) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (32 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 35); return -1; } if (addQuotes) { _sntprintf(strings[index], 32 + 1, TEXT("-Dwrapper.use_system_time=\"TRUE\"")); } else { _sntprintf(strings[index], 32 + 1, TEXT("-Dwrapper.use_system_time=TRUE")); } } index++; } else { /* Only pass the timer fast and slow thresholds to the JVM if they are not default. * These are only used if the system time is not being used. */ if (wrapperData->timerFastThreshold != WRAPPER_TIMER_FAST_THRESHOLD) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (43 + 1)); /* Allow for 10 digits */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 36); return -1; } if (addQuotes) { _sntprintf(strings[index], 43 + 1, TEXT("-Dwrapper.timer_fast_threshold=\"%d\""), wrapperData->timerFastThreshold * WRAPPER_TICK_MS / 1000); } else { _sntprintf(strings[index], 43 + 1, TEXT("-Dwrapper.timer_fast_threshold=%d"), wrapperData->timerFastThreshold * WRAPPER_TICK_MS / 1000); } } index++; } if (wrapperData->timerSlowThreshold != WRAPPER_TIMER_SLOW_THRESHOLD) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (43 + 1)); /* Allow for 10 digits */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 37); return -1; } if (addQuotes) { _sntprintf(strings[index], 43 + 1, TEXT("-Dwrapper.timer_slow_threshold=\"%d\""), wrapperData->timerSlowThreshold * WRAPPER_TICK_MS / 1000); } else { _sntprintf(strings[index], 43 + 1, TEXT("-Dwrapper.timer_slow_threshold=%d"), wrapperData->timerSlowThreshold * WRAPPER_TICK_MS / 1000); } } index++; } } /* Always write the version of the wrapper binary as a property. The * WrapperManager class uses it to verify that the version matches. */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (20 + _tcslen(wrapperVersion) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 37); return -1; } if (addQuotes) { _sntprintf(strings[index], 20 + _tcslen(wrapperVersion) + 1, TEXT("-Dwrapper.version=\"%s\""), wrapperVersion); } else { _sntprintf(strings[index], 20 + _tcslen(wrapperVersion) + 1, TEXT("-Dwrapper.version=%s"), wrapperVersion); } } index++; /* Store the base name of the native library. */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (27 + _tcslen(wrapperData->nativeLibrary) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 38); return -1; } if (addQuotes) { _sntprintf(strings[index], 27 + _tcslen(wrapperData->nativeLibrary) + 1, TEXT("-Dwrapper.native_library=\"%s\""), wrapperData->nativeLibrary); } else { _sntprintf(strings[index], 27 + _tcslen(wrapperData->nativeLibrary) + 1, TEXT("-Dwrapper.native_library=%s"), wrapperData->nativeLibrary); } } index++; /* Store the arch name of the wrapper. */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (17 + _tcslen(wrapperArch) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 39); return -1; } if (addQuotes) { _sntprintf(strings[index], 17 + _tcslen(wrapperArch) + 1, TEXT("-Dwrapper.arch=\"%s\""), wrapperArch); } else { _sntprintf(strings[index], 17 + _tcslen(wrapperArch) + 1, TEXT("-Dwrapper.arch=%s"), wrapperArch); } } index++; /* Store the ignore signals flag if configured to do so */ if (wrapperData->ignoreSignals & WRAPPER_IGNORE_SIGNALS_JAVA) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (31 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 40); return -1; } if (addQuotes) { _sntprintf(strings[index], 31 + 1, TEXT("-Dwrapper.ignore_signals=\"TRUE\"")); } else { _sntprintf(strings[index], 31 + 1, TEXT("-Dwrapper.ignore_signals=TRUE")); } } index++; } /* If this is being run as a service, add a service flag. */ if (!wrapperData->isConsole) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (24 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 41); return -1; } if (addQuotes) { _sntprintf(strings[index], 24 + 1, TEXT("-Dwrapper.service=\"TRUE\"")); } else { _sntprintf(strings[index], 24 + 1, TEXT("-Dwrapper.service=TRUE")); } } index++; } /* Store the Disable Tests flag */ if (wrapperData->isTestsDisabled) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (30 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 42); return -1; } if (addQuotes) { _sntprintf(strings[index], 30 + 1, TEXT("-Dwrapper.disable_tests=\"TRUE\"")); } else { _sntprintf(strings[index], 30 + 1, TEXT("-Dwrapper.disable_tests=TRUE")); } } index++; } /* Store the Disable Shutdown Hook flag */ if (wrapperData->isShutdownHookDisabled) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (38 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 43); return -1; } if (addQuotes) { _sntprintf(strings[index], 38 + 1, TEXT("-Dwrapper.disable_shutdown_hook=\"TRUE\"")); } else { _sntprintf(strings[index], 38 + 1, TEXT("-Dwrapper.disable_shutdown_hook=TRUE")); } } index++; } /* Store the CPU Timeout value */ if (strings) { /* Just to be safe, allow 20 characters for the timeout value */ strings[index] = malloc(sizeof(TCHAR) * (24 + 20 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 44); return -1; } if (addQuotes) { _sntprintf(strings[index], 24 + 20 + 1, TEXT("-Dwrapper.cpu.timeout=\"%d\""), wrapperData->cpuTimeout); } else { _sntprintf(strings[index], 24 + 20 + 1, TEXT("-Dwrapper.cpu.timeout=%d"), wrapperData->cpuTimeout); } } index++; if ((prop = getStringProperty(properties, TEXT("wrapper.java.outfile"), NULL))) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (25 + _tcslen(prop) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 46); return -1; } if (addQuotes) { _sntprintf(strings[index], 25 + _tcslen(prop) + 1, TEXT("-Dwrapper.java.outfile=\"%s\""), prop); } else { _sntprintf(strings[index], 25 + _tcslen(prop) + 1, TEXT("-Dwrapper.java.outfile=%s"), prop); } } index++; } if ((prop = getStringProperty(properties, TEXT("wrapper.java.errfile"), NULL))) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (25 + _tcslen(prop) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 47); return -1; } if (addQuotes) { _sntprintf(strings[index], 25 + _tcslen(prop) + 1, TEXT("-Dwrapper.java.errfile=\"%s\""), prop); } else { _sntprintf(strings[index], 25 + _tcslen(prop) + 1, TEXT("-Dwrapper.java.errfile=%s"), prop); } } index++; } /* Store the Wrapper JVM ID. (Get here before incremented) */ if (strings) { strings[index] = malloc(sizeof(TCHAR) * (16 + 5 + 1)); /* jvmid up to 5 characters */ if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 48); return -1; } _sntprintf(strings[index], 16 + 5 + 1, TEXT("-Dwrapper.jvmid=%d"), (wrapperData->jvmRestarts + 1)); } index++; /* If this JVM will be detached after startup, it needs to know that. */ if (wrapperData->detachStarted) { if (strings) { strings[index] = malloc(sizeof(TCHAR) * (30 + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 51); return -1; } if (addQuotes) { _sntprintf(strings[index], 30 + 1, TEXT("-Dwrapper.detachStarted=\"TRUE\"")); } else { _sntprintf(strings[index], 30 + 1, TEXT("-Dwrapper.detachStarted=TRUE")); } } index++; } /* Store the main class */ prop = getStringProperty(properties, TEXT("wrapper.java.mainclass"), TEXT("Main")); if (_tcscmp(prop, TEXT("org.tanukisoftware.wrapper.test.Main")) == 0) { thisIsTestWrapper = TRUE; } else { thisIsTestWrapper = FALSE; } if (strings) { strings[index] = malloc(sizeof(TCHAR) * (_tcslen(prop) + 1)); if (!strings[index]) { outOfMemory(TEXT("WBJCAI"), 52); return -1; } _sntprintf(strings[index], _tcslen(prop) + 1, TEXT("%s"), prop); } index++; /* Store any application parameters */ if ((index = wrapperBuildJavaCommandArrayAppParameters(strings, addQuotes, index, thisIsTestWrapper)) < 0) { return -1; } if ((index = wrapperLoadParameterFile(strings, addQuotes, detectDebugJVM, index, TEXT("wrapper.app.parameter_file"), FALSE)) < 0) { return -1; } return index; } /** * command is a pointer to a pointer of an array of character strings. * length is the number of strings in the above array. * * @return TRUE if there were any problems. */ int wrapperBuildJavaCommandArray(TCHAR ***stringsPtr, int *length, int addQuotes, const TCHAR *classpath) { int reqLen; /* Reset the flag stating that the JVM is a debug JVM. */ wrapperData->debugJVM = FALSE; wrapperData->debugJVMTimeoutNotified = FALSE; /* Find out how long the array needs to be first. */ reqLen = wrapperBuildJavaCommandArrayInner(NULL, addQuotes, classpath); if (reqLen < 0) { return TRUE; } *length = reqLen; /* Allocate the correct amount of memory */ *stringsPtr = malloc((*length) * sizeof **stringsPtr ); if (!(*stringsPtr)) { outOfMemory(TEXT("WBJCA"), 1); return TRUE; } /* Now actually fill in the strings */ reqLen = wrapperBuildJavaCommandArrayInner(*stringsPtr, addQuotes, classpath); if (reqLen < 0) { return TRUE; } if (wrapperData->debugJVM) { if ((wrapperData->startupTimeout > 0) || (wrapperData->pingTimeout > 0) || (wrapperData->shutdownTimeout > 0) || (wrapperData->jvmExitTimeout > 0)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("---------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT( "The JVM is being launched with a debugger enabled and could possibly\nbe suspended. To avoid unwanted shutdowns, timeouts will be\ndisabled, removing the ability to detect and restart frozen JVMs.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("---------------------------------------------------------------------") ); } } return FALSE; } void wrapperFreeJavaCommandArray(TCHAR **strings, int length) { int i; if (strings != NULL) { /* Loop over and free each of the strings in the array */ for (i = 0; i < length; i++) { if (strings[i] != NULL) { free(strings[i]); strings[i] = NULL; } } free(strings); strings = NULL; } } /** * Called when the Wrapper detects that the JVM process has exited. * Contains code common to all platforms. */ void wrapperJVMProcessExited(TICKS nowTicks, int exitCode) { int setState = TRUE; if (exitCode == 0) { /* The JVM exit code was 0, so leave any current exit code as is. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM process exited with a code of %d, leaving the wrapper exit code set to %d."), exitCode, wrapperData->exitCode); } else if (wrapperData->exitCode == 0) { /* Update the wrapper exitCode. */ wrapperData->exitCode = exitCode; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM process exited with a code of %d, setting the wrapper exit code to %d."), exitCode, wrapperData->exitCode); } else { /* The wrapper exit code was already non-zero, so leave it as is. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM process exited with a code of %d, however the wrapper exit code was already %d."), exitCode, wrapperData->exitCode); } switch(wrapperData->jState) { case WRAPPER_JSTATE_DOWN_CLEAN: case WRAPPER_JSTATE_DOWN_CHECK: case WRAPPER_JSTATE_DOWN_FLUSH: /* Shouldn't be called in this state. But just in case. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM already down.")); } setState = FALSE; break; case WRAPPER_JSTATE_LAUNCH_DELAY: /* We got a message that the JVM process died when we already thought is was down. * Most likely this was caused by a SIGCHLD signal. We are already in the expected * state so go ahead and ignore it. Do NOT go back to DOWN or the restart flag * and all restart counts will have be lost */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Received a message that the JVM is down when in the LAUNCH(DELAY) state.")); } setState = FALSE; break; case WRAPPER_JSTATE_RESTART: /* We got a message that the JVM process died when we already thought is was down. * Most likely this was caused by a SIGCHLD signal. We are already in the expected * state so go ahead and ignore it. Do NOT go back to DOWN or the restart flag * and all restart counts will have be lost */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Received a message that the JVM is down when in the RESTART state.")); } setState = FALSE; break; case WRAPPER_JSTATE_LAUNCH: /* We got a message that the JVM process died when we already thought is was down. * Most likely this was caused by a SIGCHLD signal. We are already in the expected * state so go ahead and ignore it. Do NOT go back to DOWN or the restart flag * and all restart counts will have be lost. * This can happen if the Java process dies Immediately after it is launched. It * is very rare if Java is launched, but can happen if the configuration is set to * launch something else. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Received a message that the JVM is down when in the LAUNCH state.")); } setState = FALSE; break; case WRAPPER_JSTATE_LAUNCHING: wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_AUTOMATIC; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("JVM exited while loading the application.")); break; case WRAPPER_JSTATE_LAUNCHED: /* Shouldn't be called in this state, but just in case. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_AUTOMATIC; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("JVM exited before starting the application.")); break; case WRAPPER_JSTATE_STARTING: wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_AUTOMATIC; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("JVM exited while starting the application.")); break; case WRAPPER_JSTATE_STARTED: wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_AUTOMATIC; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("JVM exited unexpectedly.")); break; case WRAPPER_JSTATE_STOP: case WRAPPER_JSTATE_STOPPING: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("JVM exited unexpectedly while stopping the application.")); break; case WRAPPER_JSTATE_STOPPED: if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM exited normally.")); } break; case WRAPPER_JSTATE_KILLING: case WRAPPER_JSTATE_KILL: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("JVM exited on its own while waiting to kill the application.")); break; case WRAPPER_JSTATE_KILLED: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JVM exited after being requested to terminate.")); break; default: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unexpected jState=%d in wrapperJVMProcessExited."), wrapperData->jState); break; } wrapperJVMDownCleanup(setState); } void wrapperBuildKey() { int i; size_t kcNum; size_t num; static int seeded = FALSE; /* Seed the randomizer */ if (!seeded) { srand((unsigned)time(NULL)); seeded = TRUE; } /* Start by generating a key */ num = _tcslen(keyChars); for (i = 0; i < 16; i++) { /* The way rand works, this will sometimes equal num, which is too big. * This is rare so just round those cases down. */ /* Some platforms use very large RAND_MAX values that cause overflow problems in our math */ if (RAND_MAX > 0x10000) { kcNum = (size_t)((rand() >> 8) * num / (RAND_MAX >> 8)); } else { kcNum = (size_t)(rand() * num / RAND_MAX); } if (kcNum >= num) { kcNum = num - 1; } wrapperData->key[i] = keyChars[kcNum]; } wrapperData->key[16] = TEXT('\0'); /* printf(" Key=%s Len=%lu\n", wrapperData->key, _tcslen(wrapperData->key)); */ } #ifdef WIN32 /* The ABOVE and BELOW normal priority class constants are not defined in MFVC 6.0 headers. */ #ifndef ABOVE_NORMAL_PRIORITY_CLASS #define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000 #endif #ifndef BELOW_NORMAL_PRIORITY_CLASS #define BELOW_NORMAL_PRIORITY_CLASS 0x00004000 #endif /** * Return FALSE if successful, TRUE if there were problems. */ int wrapperBuildNTServiceInfo() { TCHAR *work; const TCHAR *priority; size_t len; size_t valLen; size_t workLen; int i; TCHAR **propertyNames; TCHAR **propertyValues; long unsigned int *propertyIndices; if (!wrapperData->configured) { /* Load the service load order group */ updateStringValue(&wrapperData->ntServiceLoadOrderGroup, getStringProperty(properties, TEXT("wrapper.ntservice.load_order_group"), TEXT(""))); if (getStringProperties(properties, TEXT("wrapper.ntservice.dependency."), TEXT(""), wrapperData->ignoreSequenceGaps, FALSE, &propertyNames, &propertyValues, &propertyIndices)) { /* Failed */ return TRUE; } /* Build the dependency list. Decide how large the list needs to be */ len = 0; i = 0; while (propertyNames[i]) { valLen = _tcslen(propertyValues[i]); if (valLen > 0) { len += valLen + 1; } i++; } /* List must end with a double '\0'. If the list is not empty then it will end with 3. But that is fine. */ len += 2; /* Actually build the buffer */ if (wrapperData->ntServiceDependencies) { /** This is a reload, so free up the old data. */ free(wrapperData->ntServiceDependencies); wrapperData->ntServiceDependencies = NULL; } work = wrapperData->ntServiceDependencies = malloc(sizeof(TCHAR) * len); if (!work) { outOfMemory(TEXT("WBNTSI"), 1); return TRUE; } workLen = len; /* Now actually build up the list. Each value is separated with a '\0'. */ i = 0; while (propertyNames[i]) { valLen = _tcslen(propertyValues[i]); if (valLen > 0) { _tcsncpy(work, propertyValues[i], workLen); work += valLen + 1; workLen -= valLen + 1; } i++; } /* Add two more nulls to the end of the list. */ work[0] = TEXT('\0'); work[1] = TEXT('\0'); /* Memory allocated in work is stored in wrapperData. The memory should not be released here. */ work = NULL; freeStringProperties(propertyNames, propertyValues, propertyIndices); /* Set the service start type */ if (strcmpIgnoreCase(getStringProperty(properties, TEXT("wrapper.ntservice.starttype"), TEXT("DEMAND_START")), TEXT("AUTO_START")) == 0) { wrapperData->ntServiceStartType = SERVICE_AUTO_START; } else { wrapperData->ntServiceStartType = SERVICE_DEMAND_START; } /* Set the service priority class */ priority = getStringProperty(properties, TEXT("wrapper.ntservice.process_priority"), TEXT("NORMAL")); if ( (strcmpIgnoreCase(priority, TEXT("LOW")) == 0) || (strcmpIgnoreCase(priority, TEXT("IDLE")) == 0) ) { wrapperData->ntServicePriorityClass = IDLE_PRIORITY_CLASS; } else if (strcmpIgnoreCase(priority, TEXT("HIGH")) == 0) { wrapperData->ntServicePriorityClass = HIGH_PRIORITY_CLASS; } else if (strcmpIgnoreCase(priority, TEXT("REALTIME")) == 0) { wrapperData->ntServicePriorityClass = REALTIME_PRIORITY_CLASS; } else if (strcmpIgnoreCase(priority, TEXT("ABOVE_NORMAL")) == 0) { wrapperData->ntServicePriorityClass = ABOVE_NORMAL_PRIORITY_CLASS; } else if (strcmpIgnoreCase(priority, TEXT("BELOW_NORMAL")) == 0) { wrapperData->ntServicePriorityClass = BELOW_NORMAL_PRIORITY_CLASS; } else { wrapperData->ntServicePriorityClass = NORMAL_PRIORITY_CLASS; } /* Account name */ updateStringValue(&wrapperData->ntServiceAccount, getStringProperty(properties, TEXT("wrapper.ntservice.account"), NULL)); if (wrapperData->ntServiceAccount && (_tcslen(wrapperData->ntServiceAccount) <= 0)) { wrapperData->ntServiceAccount = NULL; } /* Account password */ wrapperData->ntServicePrompt = getBooleanProperty(properties, TEXT("wrapper.ntservice.account.prompt"), FALSE); if (wrapperData->ntServicePrompt == TRUE) { wrapperData->ntServicePasswordPrompt = TRUE; } else { wrapperData->ntServicePasswordPrompt = getBooleanProperty(properties, TEXT("wrapper.ntservice.password.prompt"), FALSE); } wrapperData->ntServicePasswordPromptMask = getBooleanProperty(properties, TEXT("wrapper.ntservice.password.prompt.mask"), TRUE); updateStringValue(&wrapperData->ntServicePassword, getStringProperty(properties, TEXT("wrapper.ntservice.password"), NULL)); if ( wrapperData->ntServicePassword && ( _tcslen( wrapperData->ntServicePassword ) <= 0 ) ) { wrapperData->ntServicePassword = NULL; } if (!wrapperData->ntServiceAccount) { /* If there is not account name, then the password must not be set. */ wrapperData->ntServicePassword = NULL; } /* Interactive */ wrapperData->ntServiceInteractive = getBooleanProperty(properties, TEXT("wrapper.ntservice.interactive"), FALSE); /* The interactive flag can not be set if an account is also set. */ if (wrapperData->ntServiceAccount && wrapperData->ntServiceInteractive) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Ignoring the wrapper.ntservice.interactive property because it can not be set when wrapper.ntservice.account is also set.")); wrapperData->ntServiceInteractive = FALSE; } /* Display a Console Window. */ wrapperData->ntAllocConsole = getBooleanProperty(properties, TEXT("wrapper.ntservice.console"), FALSE); /* Set the default hide wrapper console flag to the inverse of the alloc console flag. */ wrapperData->ntHideWrapperConsole = !wrapperData->ntAllocConsole; /* Hide the JVM Console Window. */ wrapperData->ntHideJVMConsole = getBooleanProperty(properties, TEXT("wrapper.ntservice.hide_console"), TRUE); /* Make sure that a console is always generated to support thread dumps */ wrapperData->generateConsole = getBooleanProperty(properties, TEXT("wrapper.ntservice.generate_console"), TRUE); } /* Set the single invocation flag. */ wrapperData->isSingleInvocation = getBooleanProperty(properties, TEXT("wrapper.single_invocation"), FALSE); wrapperData->threadDumpControlCode = getIntProperty(properties, TEXT("wrapper.thread_dump_control_code"), 255); if (wrapperData->threadDumpControlCode <= 0) { /* Disabled */ } else if ((wrapperData->threadDumpControlCode < 128) || (wrapperData->threadDumpControlCode > 255)) { wrapperData->threadDumpControlCode = 255; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Ignoring the wrapper.thread_dump_control_code property because it must be in the range 128-255 or 0.")); } return FALSE; } #endif int validateTimeout(const TCHAR* propertyName, int value) { int okValue; if (value <= 0) { okValue = 0; } else if (value > WRAPPER_TIMEOUT_MAX) { okValue = WRAPPER_TIMEOUT_MAX; } else { okValue = value; } if (okValue != value) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The value of %s must be in the range 1 to %d seconds (%d days), or 0 to disable. Changing to %d."), propertyName, WRAPPER_TIMEOUT_MAX, WRAPPER_TIMEOUT_MAX / 86400, okValue); } return okValue; } void wrapperLoadHostName() { char hostName[80]; TCHAR* hostName2; #ifdef UNICODE int len; #endif if (gethostname(hostName, sizeof(hostName))) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to obtain host name. %s"), getLastErrorText()); } else { #ifdef UNICODE #ifdef WIN32 len = MultiByteToWideChar(CP_OEMCP, 0, hostName, -1, NULL, 0); if (len <= 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Invalid multibyte sequence in port address \"%s\" : %s"), hostName, getLastErrorText()); return; } hostName2 = malloc(sizeof(LPWSTR) * (len + 1)); if (!hostName2) { outOfMemory(TEXT("LHN"), 1); return; } MultiByteToWideChar(CP_OEMCP,0, hostName, -1, hostName2, len + 1); #else len = mbstowcs(NULL, hostName, MBSTOWCS_QUERY_LENGTH); if (len == (size_t)-1) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Invalid multibyte sequence in port address \"%s\" : %s"), hostName, getLastErrorText()); return; } hostName2 = malloc(sizeof(TCHAR) * (len + 1)); if (!hostName2) { outOfMemory(TEXT("LHN"), 2); return; } mbstowcs(hostName2, hostName, len + 1); hostName2[len] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ #endif #else /* No conversion needed. Do an extra malloc here to keep the code simple below. */ len = _tcslen(hostName); hostName2 = malloc(sizeof(TCHAR) * (len + 1)); if (!hostName2) { outOfMemory(TEXT("LHN"), 3); return; } _tcsncpy(hostName2, hostName, len + 1); #endif wrapperData->hostName = malloc(sizeof(TCHAR) * (_tcslen(hostName2) + 1)); if (!wrapperData->hostName) { outOfMemory(TEXT("LHN"), 4); free(hostName2); return; } _tcsncpy(wrapperData->hostName, hostName2, _tcslen(hostName2) + 1); free(hostName2); } } /** * Resolves an action name into an actionId. * * @param actionName Action to be resolved. (Contents of buffer will be converted to upper case.) * @param propertyName The name of the property where the action name originated. * @param logErrors TRUE if errors should be logged. * * @return The action Id, or 0 if it was unknown. */ int getActionForName(TCHAR *actionName, const TCHAR *propertyName, int logErrors) { size_t len; size_t i; int action; /* We need the actionName in upper case. */ len = _tcslen(actionName); for (i = 0; i < len; i++) { actionName[i] = _totupper(actionName[i]); } if (_tcscmp(actionName, TEXT("RESTART")) == 0) { action = ACTION_RESTART; } else if (_tcscmp(actionName, TEXT("SHUTDOWN")) == 0) { action = ACTION_SHUTDOWN; } else if (_tcscmp(actionName, TEXT("DUMP")) == 0) { action = ACTION_DUMP; } else if (_tcscmp(actionName, TEXT("NONE")) == 0) { action = ACTION_NONE; } else if (_tcscmp(actionName, TEXT("DEBUG")) == 0) { action = ACTION_DEBUG; } else if (_tcscmp(actionName, TEXT("SUCCESS")) == 0) { action = ACTION_SUCCESS; } else if (_tcscmp(actionName, TEXT("GC")) == 0) { action = ACTION_GC; } else if (_tcscmp(actionName, TEXT("PAUSE")) == 0) { if (logErrors) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Pause actions require the Standard Edition. Ignoring action '%s' in the %s property."), actionName, propertyName); } action = 0; } else if (_tcscmp(actionName, TEXT("RESUME")) == 0) { if (logErrors) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Resume actions require the Standard Edition. Ignoring action '%s' in the %s property."), actionName, propertyName); } action = 0; } else if (_tcsstr(actionName, TEXT("USER_")) == actionName) { if (logErrors) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("User actions require the Professional Edition. Ignoring action '%s' in the %s property."), actionName, propertyName); } action = 0; } else { if (logErrors) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Encountered an unknown action '%s' in the %s property. Skipping."), actionName, propertyName); } action = 0; } return action; } /** * Parses a list of actions for an action property. * * @param actionNameList A space separated list of action names. * @param propertyName The name of the property where the action name originated. * * @return an array of integer action ids, or NULL if there were any problems. */ int *wrapperGetActionListForNames(const TCHAR *actionNameList, const TCHAR *propertyName) { size_t len; TCHAR *workBuffer; TCHAR *token; int actionCount; int action; int *actionList = NULL; #if defined(UNICODE) && !defined(WIN32) TCHAR *state; #endif #if _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("wrapperGetActionListForNames(%s, %s)"), actionNameList, propertyName); #endif /* First get a count of the number of valid actions. */ len = _tcslen(actionNameList); workBuffer = malloc(sizeof(TCHAR) * (len + 1)); if (!workBuffer) { outOfMemory(TEXT("GALFN"), 1); } else { actionCount = 0; _tcsncpy(workBuffer, actionNameList, len + 1); token = _tcstok(workBuffer, TEXT(" ,") #if defined(UNICODE) && !defined(WIN32) , &state #endif ); while (token != NULL) { action = getActionForName(token, propertyName, TRUE); if (action == 0) { /* Unknown action */ } else { actionCount++; } #if _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT(" action='%s' -> %d"), token, action); #endif token = _tcstok(NULL, TEXT(" ,") #if defined(UNICODE) && !defined(WIN32) , &state #endif ); } /* Add ACTION_LIST_END */ actionCount++; /* Create the action list to return. */ actionList = malloc(sizeof(int) * actionCount); if (!actionList) { outOfMemory(TEXT("GALFN"), 2); } else { /* Now actually pull out the actions */ actionCount = 0; _tcsncpy(workBuffer, actionNameList, len + 1); token = _tcstok(workBuffer, TEXT(" ,") #if defined(UNICODE) && !defined(WIN32) , &state #endif ); while (token != NULL) { action = getActionForName(token, propertyName, FALSE); if (action == 0) { /* Unknown action */ } else { actionList[actionCount] = action; actionCount++; } token = _tcstok(NULL, TEXT(" ,") #if defined(UNICODE) && !defined(WIN32) , &state #endif ); } /* Add ACTION_LIST_END */ actionList[actionCount] = ACTION_LIST_END; actionCount++; /* actionList returned, so don't free it. */ } free(workBuffer); } return actionList; } /** * Loads in the configuration triggers. * * @return Returns FALSE if successful, TRUE if there were any problems. */ int loadConfigurationTriggers() { const TCHAR *prop; TCHAR propName[256]; int i; TCHAR **propertyNames; TCHAR **propertyValues; long unsigned int *propertyIndices; #ifdef _DEBUG int j; #endif /* To support reloading, we need to free up any previously loaded filters. */ if (wrapperData->outputFilterCount > 0) { for (i = 0; i < wrapperData->outputFilterCount; i++) { free(wrapperData->outputFilters[i]); wrapperData->outputFilters[i] = NULL; } free(wrapperData->outputFilters); wrapperData->outputFilters = NULL; if (wrapperData->outputFilterActionLists) { for (i = 0; i < wrapperData->outputFilterCount; i++) { free(wrapperData->outputFilterActionLists[i]); wrapperData->outputFilterActionLists[i] = NULL; } free(wrapperData->outputFilterActionLists); wrapperData->outputFilterActionLists = NULL; } /* Individual messages are references to property values and are not malloced. */ free(wrapperData->outputFilterMessages); wrapperData->outputFilterMessages = NULL; free(wrapperData->outputFilterAllowWildFlags); wrapperData->outputFilterAllowWildFlags = NULL; free(wrapperData->outputFilterMinLens); wrapperData->outputFilterMinLens = NULL; } wrapperData->outputFilterCount = 0; if (getStringProperties(properties, TEXT("wrapper.filter.trigger."), TEXT(""), wrapperData->ignoreSequenceGaps, FALSE, &propertyNames, &propertyValues, &propertyIndices)) { /* Failed */ return TRUE; } /* Loop over the properties and count how many triggers there are. */ i = 0; while (propertyNames[i]) { wrapperData->outputFilterCount++; i++; } #if defined(MACOSX) wrapperData->outputFilterCount++; i++; #endif /* Now that a count is known, allocate memory to hold the filters and actions and load them in. */ if (wrapperData->outputFilterCount > 0) { wrapperData->outputFilters = malloc(sizeof(TCHAR *) * wrapperData->outputFilterCount); if (!wrapperData->outputFilters) { outOfMemory(TEXT("LC"), 1); return TRUE; } memset(wrapperData->outputFilters, 0, sizeof(TCHAR *) * wrapperData->outputFilterCount); wrapperData->outputFilterActionLists = malloc(sizeof(int*) * wrapperData->outputFilterCount); if (!wrapperData->outputFilterActionLists) { outOfMemory(TEXT("LC"), 2); return TRUE; } memset(wrapperData->outputFilterActionLists, 0, sizeof(int*) * wrapperData->outputFilterCount); wrapperData->outputFilterMessages = malloc(sizeof(TCHAR *) * wrapperData->outputFilterCount); if (!wrapperData->outputFilterMessages) { outOfMemory(TEXT("LC"), 3); return TRUE; } wrapperData->outputFilterAllowWildFlags = malloc(sizeof(int) * wrapperData->outputFilterCount); if (!wrapperData->outputFilterAllowWildFlags) { outOfMemory(TEXT("LC"), 4); return TRUE; } memset(wrapperData->outputFilterAllowWildFlags, 0, sizeof(int) * wrapperData->outputFilterCount); wrapperData->outputFilterMinLens = malloc(sizeof(size_t) * wrapperData->outputFilterCount); if (!wrapperData->outputFilterMinLens) { outOfMemory(TEXT("LC"), 5); return TRUE; } memset(wrapperData->outputFilterMinLens, 0, sizeof(size_t) * wrapperData->outputFilterCount); i = 0; while (propertyNames[i]) { prop = propertyValues[i]; wrapperData->outputFilters[i] = malloc(sizeof(TCHAR) * (_tcslen(prop) + 1)); if (!wrapperData->outputFilters[i]) { outOfMemory(TEXT("LC"), 3); return TRUE; } _tcsncpy(wrapperData->outputFilters[i], prop, _tcslen(prop) + 1); /* Get the action */ _sntprintf(propName, 256, TEXT("wrapper.filter.action.%lu"), propertyIndices[i]); prop = getStringProperty(properties, propName, TEXT("RESTART")); wrapperData->outputFilterActionLists[i] = wrapperGetActionListForNames(prop, propName); /* Get the message */ _sntprintf(propName, 256, TEXT("wrapper.filter.message.%lu"), propertyIndices[i]); prop = getStringProperty(properties, propName, NULL); wrapperData->outputFilterMessages[i] = (TCHAR *)prop; /* Get the wildcard flags. */ _sntprintf(propName, 256, TEXT("wrapper.filter.allow_wildcards.%lu"), propertyIndices[i]); wrapperData->outputFilterAllowWildFlags[i] = getBooleanProperty(properties, propName, FALSE); if (wrapperData->outputFilterAllowWildFlags[i]) { /* Calculate the minimum text length. */ wrapperData->outputFilterMinLens[i] = wrapperGetMinimumTextLengthForPattern(wrapperData->outputFilters[i]); } #ifdef _DEBUG _tprintf(TEXT("filter #%lu, actions=("), propertyIndices[i]); if (wrapperData->outputFilterActionLists[i]) { j = 0; while (wrapperData->outputFilterActionLists[i][j]) { if (j > 0) { _tprintf(TEXT(",")); } _tprintf(TEXT("%d"), wrapperData->outputFilterActionLists[i][j]); j++; } } _tprintf(TEXT("), filter='%s'\n"), wrapperData->outputFilters[i]); #endif i++; } #if defined(MACOSX) wrapperData->outputFilters[i] = malloc(sizeof(TCHAR) * (_tcslen(TRIGGER_ADVICE_NIL_SERVER) + 1)); if (!wrapperData->outputFilters[i]) { outOfMemory(TEXT("LC"), 4); return TRUE; } _tcsncpy(wrapperData->outputFilters[i], TRIGGER_ADVICE_NIL_SERVER, _tcslen(TRIGGER_ADVICE_NIL_SERVER) + 1); wrapperData->outputFilterActionLists[i] = malloc(sizeof(int) * 2); if (!wrapperData->outputFilters[i]) { outOfMemory(TEXT("LC"), 5); return TRUE; } wrapperData->outputFilterActionLists[i][0] = ACTION_ADVICE_NIL_SERVER; wrapperData->outputFilterActionLists[i][1] = ACTION_LIST_END; wrapperData->outputFilterMessages[i] = NULL; wrapperData->outputFilterAllowWildFlags[i] = FALSE; wrapperData->outputFilterMinLens[i] = 0; i++; #endif } freeStringProperties(propertyNames, propertyValues, propertyIndices); return FALSE; } int getBackendTypeForName(const TCHAR *typeName) { if (strcmpIgnoreCase(typeName, TEXT("SOCKET")) == 0) { return WRAPPER_BACKEND_TYPE_SOCKET; } else if (strcmpIgnoreCase(typeName, TEXT("SOCKET_IPv4")) == 0) { return WRAPPER_BACKEND_TYPE_SOCKET_V4; } else if (strcmpIgnoreCase(typeName, TEXT("SOCKET_IPv6")) == 0) { return WRAPPER_BACKEND_TYPE_SOCKET_V6; } else if (strcmpIgnoreCase(typeName, TEXT("PIPE")) == 0) { return WRAPPER_BACKEND_TYPE_PIPE; } else if (strcmpIgnoreCase(typeName, TEXT("AUTO")) == 0) { return WRAPPER_BACKEND_TYPE_AUTO; } else { return WRAPPER_BACKEND_TYPE_UNKNOWN; } } /** * Return FALSE if successful, TRUE if there were problems. */ int loadConfiguration() { TCHAR propName[256]; const TCHAR* val; int startupDelay; wrapperLoadLoggingProperties(FALSE); /* Decide on the backend type to use. */ val = getStringProperty(properties, TEXT("wrapper.backend.type"), TEXT("AUTO")); wrapperData->backendType = getBackendTypeForName(val); if (wrapperData->backendType == WRAPPER_BACKEND_TYPE_UNKNOWN) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Unknown value for wrapper.backend.type: %s. Setting it to AUTO."), val); wrapperData->backendType = WRAPPER_BACKEND_TYPE_AUTO; } /* Decide whether the classpath should be passed via the environment. */ wrapperData->environmentClasspath = getBooleanProperty(properties, TEXT("wrapper.java.classpath.use_environment"), FALSE); /* Decide how sequence gaps should be handled before any other properties are loaded. */ wrapperData->ignoreSequenceGaps = getBooleanProperty(properties, TEXT("wrapper.ignore_sequence_gaps"), FALSE); /* Make sure that the configured log file directory is accessible. */ checkLogfileDir(); /* To make configuration reloading work correctly with changes to the log file, * it needs to be closed here. */ closeLogfile(); /* Maintain the logger just in case we wrote any queued errors. */ maintainLogger(); /* Because the first call could cause errors as well, do it again to clear them out. * This is only a one-time thing on startup as we test the new logfile configuration. */ maintainLogger(); /* Initialize some values not loaded */ wrapperData->exitCode = 0; updateStringValue(&wrapperData->portAddress, getStringProperty(properties, TEXT("wrapper.port.address"), NULL)); /* Get the port. The int will wrap within the 0-65535 valid range, so no need to test the value. */ wrapperData->port = getIntProperty(properties, TEXT("wrapper.port"), 0); wrapperData->portMin = getIntProperty(properties, TEXT("wrapper.port.min"), 32000); if ((wrapperData->portMin < 1) || (wrapperData->portMin > 65535)) { wrapperData->portMin = 32000; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s must be in the range %d to %d. Changing to %d."), TEXT("wrapper.port.min"), 1, 65535, wrapperData->portMin); } wrapperData->portMax = getIntProperty(properties, TEXT("wrapper.port.max"), 32999); if ((wrapperData->portMax < 1) || (wrapperData->portMax > 65535)) { wrapperData->portMax = __min(wrapperData->portMin + 999, 65535); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s must be in the range %d to %d. Changing to %d."), TEXT("wrapper.port.max"), 1, 65535, wrapperData->portMax); } else if (wrapperData->portMax < wrapperData->portMin) { wrapperData->portMax = __min(wrapperData->portMin + 999, 65535); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s must be greater than or equal to %s. Changing to %d."), TEXT("wrapper.port.max"), TEXT("wrapper.port.min"), wrapperData->portMax); } /* Get the port for the JVM side of the socket. */ wrapperData->jvmPort = getIntProperty(properties, TEXT("wrapper.jvm.port"), -1); if (wrapperData->jvmPort > 0) { if (wrapperData->jvmPort == wrapperData->port) { wrapperData->jvmPort = -1; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("wrapper.jvm.port must not equal wrapper.port. Changing to the default.")); } } wrapperData->jvmPortMin = getIntProperty(properties, TEXT("wrapper.jvm.port.min"), 31000); if ((wrapperData->jvmPortMin < 1) || (wrapperData->jvmPortMin > 65535)) { wrapperData->jvmPortMin = 31000; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s must be in the range %d to %d. Changing to %d."), TEXT("wrapper.jvm.port.min"), 1, 65535, wrapperData->jvmPortMin); } wrapperData->jvmPortMax = getIntProperty(properties, TEXT("wrapper.jvm.port.max"), 31999); if ((wrapperData->jvmPortMax < 1) || (wrapperData->jvmPortMax > 65535)) { wrapperData->jvmPortMax = __min(wrapperData->jvmPortMin + 999, 65535); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s must be in the range %d to %d. Changing to %d."), TEXT("wrapper.jvm.port.max"), 1, 65535, wrapperData->jvmPortMax); } else if (wrapperData->jvmPortMax < wrapperData->jvmPortMin) { wrapperData->jvmPortMax = __min(wrapperData->jvmPortMin + 999, 65535); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s must be greater than or equal to %s. Changing to %d."), TEXT("wrapper.jvm.port.max"), TEXT("wrapper.jvm.port.min"), wrapperData->jvmPortMax); } wrapperData->printJVMVersion = getBooleanProperty(properties, TEXT("wrapper.java.version.output"), FALSE); /* Get the wrapper command log level. */ wrapperData->commandLogLevel = getLogLevelForName( getStringProperty(properties, TEXT("wrapper.java.command.loglevel"), TEXT("DEBUG"))); if (wrapperData->commandLogLevel >= LEVEL_NONE) { /* Should never be possible to completely disable the java command as this would make it very difficult to support. */ wrapperData->commandLogLevel = LEVEL_DEBUG; } /* Should we detach the JVM on startup. */ if (wrapperData->isConsole) { wrapperData->detachStarted = getBooleanProperty(properties, TEXT("wrapper.jvm_detach_started"), FALSE); } /* Get the adviser status */ wrapperData->isAdviserEnabled = getBooleanProperty(properties, TEXT("wrapper.adviser"), TRUE); /* The adviser is always enabled if debug is enabled. */ if (wrapperData->isDebugging) { wrapperData->isAdviserEnabled = TRUE; } /* Get the use system time flag. */ if (!wrapperData->configured) { wrapperData->useSystemTime = getBooleanProperty(properties, TEXT("wrapper.use_system_time"), FALSE); } if (!wrapperData->configured) { wrapperData->logBufferGrowth = getBooleanProperty(properties, TEXT("wrapper.log_buffer_growth"), FALSE); setLogBufferGrowth(wrapperData->logBufferGrowth); } #ifdef WIN32 /* Get the use javaio buffer size. */ if (!wrapperData->configured) { wrapperData->javaIOBufferSize = getIntProperty(properties, TEXT("wrapper.javaio.buffer_size"), WRAPPER_JAVAIO_BUFFER_SIZE_DEFAULT); if (wrapperData->javaIOBufferSize == WRAPPER_JAVAIO_BUFFER_SIZE_SYSTEM_DEFAULT) { /* Ok. System default buffer size. */ } else if (wrapperData->javaIOBufferSize < WRAPPER_JAVAIO_BUFFER_SIZE_MIN) { wrapperData->javaIOBufferSize = WRAPPER_JAVAIO_BUFFER_SIZE_MIN; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s must be in the range %d to %d or %d. Changing to %d."), TEXT("wrapper.javaio.buffer_size"), WRAPPER_JAVAIO_BUFFER_SIZE_MIN, WRAPPER_JAVAIO_BUFFER_SIZE_MAX, WRAPPER_JAVAIO_BUFFER_SIZE_SYSTEM_DEFAULT, wrapperData->javaIOBufferSize); } else if (wrapperData->javaIOBufferSize > WRAPPER_JAVAIO_BUFFER_SIZE_MAX) { wrapperData->javaIOBufferSize = WRAPPER_JAVAIO_BUFFER_SIZE_MAX; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s must be in the range %d to %d or %d. Changing to %d."), TEXT("wrapper.javaio.buffer_size"), WRAPPER_JAVAIO_BUFFER_SIZE_MIN, WRAPPER_JAVAIO_BUFFER_SIZE_MAX, WRAPPER_JAVAIO_BUFFER_SIZE_SYSTEM_DEFAULT, wrapperData->javaIOBufferSize); } } #endif /* Get the use javaio thread flag. */ if (!wrapperData->configured) { wrapperData->useJavaIOThread = getBooleanProperty(properties, TEXT("wrapper.javaio.use_thread"), getBooleanProperty(properties, TEXT("wrapper.use_javaio_thread"), FALSE)); } /* Decide whether or not a mutex should be used to protect the tick timer. */ if (!wrapperData->configured) { wrapperData->useTickMutex = getBooleanProperty(properties, TEXT("wrapper.use_tick_mutex"), FALSE); } /* Get the timer thresholds. Properties are in seconds, but internally we use ticks. */ wrapperData->timerFastThreshold = getIntProperty(properties, TEXT("wrapper.timer_fast_threshold"), WRAPPER_TIMER_FAST_THRESHOLD * WRAPPER_TICK_MS / 1000) * 1000 / WRAPPER_TICK_MS; wrapperData->timerSlowThreshold = getIntProperty(properties, TEXT("wrapper.timer_slow_threshold"), WRAPPER_TIMER_SLOW_THRESHOLD * WRAPPER_TICK_MS / 1000) * 1000 / WRAPPER_TICK_MS; /* Load the name of the native library to be loaded. */ wrapperData->nativeLibrary = getStringProperty(properties, TEXT("wrapper.native_library"), TEXT("wrapper")); /* Get the append PATH to library path flag. */ wrapperData->libraryPathAppendPath = getBooleanProperty(properties, TEXT("wrapper.java.library.path.append_system_path"), FALSE); /* Get the state output status. */ wrapperData->isStateOutputEnabled = getBooleanProperty(properties, TEXT("wrapper.state_output"), FALSE); /* Get the tick output status. */ wrapperData->isTickOutputEnabled = getBooleanProperty(properties, TEXT("wrapper.tick_output"), FALSE); /* Get the loop debug output status. */ wrapperData->isLoopOutputEnabled = getBooleanProperty(properties, TEXT("wrapper.loop_output"), FALSE); /* Get the sleep debug output status. */ wrapperData->isSleepOutputEnabled = getBooleanProperty(properties, TEXT("wrapper.sleep_output"), FALSE); /* Get the memory output status. */ wrapperData->isMemoryOutputEnabled = getBooleanProperty(properties, TEXT("wrapper.memory_output"), FALSE); wrapperData->memoryOutputInterval = getIntProperty(properties, TEXT("wrapper.memory_output.interval"), 1); /* Get the cpu output status. */ wrapperData->isCPUOutputEnabled = getBooleanProperty(properties, TEXT("wrapper.cpu_output"), FALSE); wrapperData->cpuOutputInterval = getIntProperty(properties, TEXT("wrapper.cpu_output.interval"), 1); /* Get the pageFault output status. */ if (!wrapperData->configured) { wrapperData->isPageFaultOutputEnabled = getBooleanProperty(properties, TEXT("wrapper.pagefault_output"), FALSE); wrapperData->pageFaultOutputInterval = getIntProperty(properties, TEXT("wrapper.pagefault_output.interval"), 1); } /* Get the disable tests flag. */ wrapperData->isTestsDisabled = getBooleanProperty(properties, TEXT("wrapper.disable_tests"), FALSE); /* Get the shutdown hook status */ wrapperData->isShutdownHookDisabled = getBooleanProperty(properties, TEXT("wrapper.disable_shutdown_hook"), FALSE); /* Get the forced shutdown flag status. */ wrapperData->isForcedShutdownDisabled = getBooleanProperty(properties, TEXT("wrapper.disable_forced_shutdown"), FALSE); /* Get the startup delay. */ startupDelay = getIntProperty(properties, TEXT("wrapper.startup.delay"), 0); wrapperData->startupDelayConsole = getIntProperty(properties, TEXT("wrapper.startup.delay.console"), startupDelay); if (wrapperData->startupDelayConsole < 0) { wrapperData->startupDelayConsole = 0; } wrapperData->startupDelayService = getIntProperty(properties, TEXT("wrapper.startup.delay.service"), startupDelay); if (wrapperData->startupDelayService < 0) { wrapperData->startupDelayService = 0; } /* Get the restart delay. */ wrapperData->restartDelay = getIntProperty(properties, TEXT("wrapper.restart.delay"), 5); if (wrapperData->restartDelay < 0) { wrapperData->restartDelay = 0; } /* Get the flag which decides whether or not configuration should be reloaded on JVM restart. */ wrapperData->restartReloadConf = getBooleanProperty(properties, TEXT("wrapper.restart.reload_configuration"), FALSE); /* Get the disable restart flag */ wrapperData->isRestartDisabled = getBooleanProperty(properties, TEXT("wrapper.disable_restarts"), FALSE); wrapperData->isAutoRestartDisabled = getBooleanProperty(properties, TEXT("wrapper.disable_restarts.automatic"), wrapperData->isRestartDisabled); /* Get the timeout settings */ wrapperData->cpuTimeout = getIntProperty(properties, TEXT("wrapper.cpu.timeout"), 10); wrapperData->startupTimeout = getIntProperty(properties, TEXT("wrapper.startup.timeout"), 30); wrapperData->pingTimeout = getIntProperty(properties, TEXT("wrapper.ping.timeout"), 30); if (wrapperData->pingActionList) { free(wrapperData->pingActionList); } wrapperData->pingActionList = wrapperGetActionListForNames(getStringProperty(properties, TEXT("wrapper.ping.timeout.action"), TEXT("RESTART")), TEXT("wrapper.ping.timeout.action")); wrapperData->pingAlertThreshold = getIntProperty(properties, TEXT("wrapper.ping.alert.threshold"), __max(1, wrapperData->pingTimeout / 4)); wrapperData->pingAlertLogLevel = getLogLevelForName(getStringProperty(properties, TEXT("wrapper.ping.alert.loglevel"), TEXT("STATUS"))); wrapperData->pingInterval = getIntProperty(properties, TEXT("wrapper.ping.interval"), 5); wrapperData->pingIntervalLogged = getIntProperty(properties, TEXT("wrapper.ping.interval.logged"), 1); wrapperData->shutdownTimeout = getIntProperty(properties, TEXT("wrapper.shutdown.timeout"), 30); wrapperData->jvmExitTimeout = getIntProperty(properties, TEXT("wrapper.jvm_exit.timeout"), 15); wrapperData->jvmCleanupTimeout = getIntProperty(properties, TEXT("wrapper.jvm_cleanup.timeout"), 10); wrapperData->jvmTerminateTimeout = getIntProperty(properties, TEXT("wrapper.jvm_terminate.timeout"), 10); wrapperData->cpuTimeout = validateTimeout(TEXT("wrapper.cpu.timeout"), wrapperData->cpuTimeout); wrapperData->startupTimeout = validateTimeout(TEXT("wrapper.startup.timeout"), wrapperData->startupTimeout); wrapperData->pingTimeout = validateTimeout(TEXT("wrapper.ping.timeout"), wrapperData->pingTimeout); wrapperData->shutdownTimeout = validateTimeout(TEXT("wrapper.shutdown.timeout"), wrapperData->shutdownTimeout); wrapperData->jvmExitTimeout = validateTimeout(TEXT("wrapper.jvm_exit.timeout"), wrapperData->jvmExitTimeout); wrapperData->jvmTerminateTimeout = validateTimeout(TEXT("wrapper.jvm_terminate.timeout"), wrapperData->jvmTerminateTimeout); wrapperData->jvmCleanupTimeout = validateTimeout(TEXT("wrapper.jvm_cleanup.timeout"), wrapperData->jvmCleanupTimeout); if (wrapperData->pingInterval < 1) { wrapperData->pingInterval = 1; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The value of %s must be at least %d second(s). Changing to %d."), TEXT("wrapper.ping.interval"), 1, wrapperData->pingInterval); } else if (wrapperData->pingInterval > 3600) { wrapperData->pingInterval = 3600; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("wrapper.ping.interval must be less than or equal to 1 hour (3600 seconds). Changing to 3600.")); } if (wrapperData->pingIntervalLogged < 1) { wrapperData->pingIntervalLogged = 1; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The value of %s must be at least %d second(s). Changing to %d."), TEXT("wrapper.ping.interval.logged"), 1, wrapperData->pingIntervalLogged); } else if (wrapperData->pingIntervalLogged > 86400) { wrapperData->pingIntervalLogged = 86400; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("wrapper.ping.interval.logged must be less than or equal to 1 day (86400 seconds). Changing to 86400.")); } if ((wrapperData->pingTimeout > 0) && (wrapperData->pingTimeout < wrapperData->pingInterval + 5)) { wrapperData->pingTimeout = wrapperData->pingInterval + 5; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("wrapper.ping.timeout must be at least 5 seconds longer than wrapper.ping.interval. Changing to %d."), wrapperData->pingTimeout); } if (wrapperData->pingAlertThreshold <= 0) { /* Ping Alerts disabled. */ wrapperData->pingAlertThreshold = 0; } else if ((wrapperData->pingTimeout > 0) && (wrapperData->pingAlertThreshold > wrapperData->pingTimeout)) { wrapperData->pingAlertThreshold = wrapperData->pingTimeout; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("wrapper.ping.alert.threshold must be less than or equal to the value of wrapper.ping.timeout (%d seconds). Changing to %d."), wrapperData->pingInterval, wrapperData->pingTimeout); } if (wrapperData->cpuTimeout > 0) { /* Make sure that the timeouts are all longer than the cpu timeout. */ if ((wrapperData->startupTimeout > 0) && (wrapperData->startupTimeout < wrapperData->cpuTimeout)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("CPU timeout detection may not operate correctly during startup because wrapper.cpu.timeout is not smaller than wrapper.startup.timeout.")); } if ((wrapperData->pingTimeout > 0) && (wrapperData->pingTimeout < wrapperData->cpuTimeout)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("CPU timeout detection may not operate correctly because wrapper.cpu.timeout is not smaller than wrapper.ping.timeout.")); } if ((wrapperData->shutdownTimeout > 0) && (wrapperData->shutdownTimeout < wrapperData->cpuTimeout)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("CPU timeout detection may not operate correctly during shutdown because wrapper.cpu.timeout is not smaller than wrapper.shutdown.timeout.")); } /* jvmExit timeout can be shorter than the cpu timeout. */ } /* Load properties controlling the number times the JVM can be restarted. */ wrapperData->maxFailedInvocations = getIntProperty(properties, TEXT("wrapper.max_failed_invocations"), 5); wrapperData->successfulInvocationTime = getIntProperty(properties, TEXT("wrapper.successful_invocation_time"), 300); if (wrapperData->maxFailedInvocations < 1) { wrapperData->maxFailedInvocations = 1; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The value of %s must be at least %d second(s). Changing to %d."), TEXT("wrapper.max_failed_invocations"), 1, wrapperData->maxFailedInvocations); } /* TRUE if the JVM should be asked to dump its state when it fails to halt on request. */ wrapperData->requestThreadDumpOnFailedJVMExit = getBooleanProperty(properties, TEXT("wrapper.request_thread_dump_on_failed_jvm_exit"), FALSE); wrapperData->requestThreadDumpOnFailedJVMExitDelay = getIntProperty(properties, TEXT("wrapper.request_thread_dump_on_failed_jvm_exit.delay"), 5); if (wrapperData->requestThreadDumpOnFailedJVMExitDelay < 1) { wrapperData->requestThreadDumpOnFailedJVMExitDelay = 1; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The value of %s must be at least %d second(s). Changing to %d."), TEXT("wrapper.request_thread_dump_on_failed_jvm_exit.delay"), 1, wrapperData->requestThreadDumpOnFailedJVMExitDelay); } /* Load the output filters. */ if (loadConfigurationTriggers()) { return TRUE; } /** Get the pid files if any. May be NULL */ if (!wrapperData->configured) { updateStringValue(&wrapperData->pidFilename, getFileSafeStringProperty(properties, TEXT("wrapper.pidfile"), NULL)); wrapperCorrectWindowsPath(wrapperData->pidFilename); } wrapperData->pidFileStrict = getBooleanProperty(properties, TEXT("wrapper.pidfile.strict"), FALSE); updateStringValue(&wrapperData->javaPidFilename, getFileSafeStringProperty(properties, TEXT("wrapper.java.pidfile"), NULL)); wrapperCorrectWindowsPath(wrapperData->javaPidFilename); /** Get the lock file if any. May be NULL */ if (!wrapperData->configured) { updateStringValue(&wrapperData->lockFilename, getFileSafeStringProperty(properties, TEXT("wrapper.lockfile"), NULL)); wrapperCorrectWindowsPath(wrapperData->lockFilename); } /** Get the java id file. May be NULL */ updateStringValue(&wrapperData->javaIdFilename, getFileSafeStringProperty(properties, TEXT("wrapper.java.idfile"), NULL)); wrapperCorrectWindowsPath(wrapperData->javaIdFilename); /** Get the status files if any. May be NULL */ if (!wrapperData->configured) { updateStringValue(&wrapperData->statusFilename, getFileSafeStringProperty(properties, TEXT("wrapper.statusfile"), NULL)); wrapperCorrectWindowsPath(wrapperData->statusFilename); } updateStringValue(&wrapperData->javaStatusFilename, getFileSafeStringProperty(properties, TEXT("wrapper.java.statusfile"), NULL)); wrapperCorrectWindowsPath(wrapperData->javaStatusFilename); /** Get the command file if any. May be NULL */ updateStringValue(&wrapperData->commandFilename, getFileSafeStringProperty(properties, TEXT("wrapper.commandfile"), NULL)); wrapperCorrectWindowsPath(wrapperData->commandFilename); wrapperData->commandFileTests = getBooleanProperty(properties, TEXT("wrapper.commandfile.enable_tests"), FALSE); /** Get the interval at which the command file will be polled. */ wrapperData->commandPollInterval = propIntMin(propIntMax(getIntProperty(properties, TEXT("wrapper.command.poll_interval"), 5), 1), 3600); /** Get the anchor file if any. May be NULL */ if (!wrapperData->configured) { updateStringValue(&wrapperData->anchorFilename, getFileSafeStringProperty(properties, TEXT("wrapper.anchorfile"), NULL)); wrapperCorrectWindowsPath(wrapperData->anchorFilename); } /** Get the interval at which the anchor file will be polled. */ wrapperData->anchorPollInterval = propIntMin(propIntMax(getIntProperty(properties, TEXT("wrapper.anchor.poll_interval"), 5), 1), 3600); /** Flag controlling whether or not system signals should be ignored. */ val = getStringProperty(properties, TEXT("wrapper.ignore_signals"), TEXT("FALSE")); if ( ( strcmpIgnoreCase( val, TEXT("TRUE") ) == 0 ) || ( strcmpIgnoreCase( val, TEXT("BOTH") ) == 0 ) ) { wrapperData->ignoreSignals = WRAPPER_IGNORE_SIGNALS_WRAPPER + WRAPPER_IGNORE_SIGNALS_JAVA; } else if ( strcmpIgnoreCase( val, TEXT("WRAPPER") ) == 0 ) { wrapperData->ignoreSignals = WRAPPER_IGNORE_SIGNALS_WRAPPER; } else if ( strcmpIgnoreCase( val, TEXT("JAVA") ) == 0 ) { wrapperData->ignoreSignals = WRAPPER_IGNORE_SIGNALS_JAVA; } else { wrapperData->ignoreSignals = 0; } /* Obtain the Console Title. */ _sntprintf(propName, 256, TEXT("wrapper.console.title.%s"), wrapperOS); updateStringValue(&wrapperData->consoleTitle, getStringProperty(properties, propName, getStringProperty(properties, TEXT("wrapper.console.title"), NULL))); /* Load the service name (Used to be windows specific so use those properties if set.) */ updateStringValue(&wrapperData->serviceName, getStringProperty(properties, TEXT("wrapper.name"), getStringProperty(properties, TEXT("wrapper.ntservice.name"), TEXT("wrapper")))); /* Load the service display name (Used to be windows specific so use those properties if set.) */ updateStringValue(&wrapperData->serviceDisplayName, getStringProperty(properties, TEXT("wrapper.displayname"), getStringProperty(properties, TEXT("wrapper.ntservice.displayname"), wrapperData->serviceName))); /* Load the service description, default to display name (Used to be windows specific so use those properties if set.) */ updateStringValue(&wrapperData->serviceDescription, getStringProperty(properties, TEXT("wrapper.description"), getStringProperty(properties, TEXT("wrapper.ntservice.description"), wrapperData->serviceDisplayName))); /* Pausable */ wrapperData->pausable = getBooleanProperty(properties, TEXT("wrapper.pausable"), getBooleanProperty(properties, TEXT("wrapper.ntservice.pausable"), FALSE)); wrapperData->pausableStopJVM = getBooleanProperty(properties, TEXT("wrapper.pausable.stop_jvm"), getBooleanProperty(properties, TEXT("wrapper.ntservice.pausable.stop_jvm"), TRUE)); if (!wrapperData->configured) { wrapperData->initiallyPaused = getBooleanProperty(properties, TEXT("wrapper.pause_on_startup"), FALSE); } #ifdef WIN32 wrapperData->ignoreUserLogoffs = getBooleanProperty(properties, TEXT("wrapper.ignore_user_logoffs"), FALSE); /* Configure the NT service information */ if (wrapperBuildNTServiceInfo()) { return TRUE; } if (wrapperData->generateConsole) { if (!wrapperData->ntAllocConsole) { /* We need to allocate a console in order for the thread dumps to work * when running as a service. But the user did not request that a * console be visible so we want to hide it. */ wrapperData->ntAllocConsole = TRUE; wrapperData->ntHideWrapperConsole = TRUE; } } #ifdef WIN32 if ((!strcmpIgnoreCase(wrapperData->argCommand, TEXT("s")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-service"))) && (!wrapperData->ntAllocConsole || wrapperData->ntHideWrapperConsole)) { #else if (!wrapperData->isConsole) { #endif /* The console is not visible, so we shouldn't waste time logging to it. */ setConsoleLogLevelInt(LEVEL_NONE); } #else /* UNIX */ /* Configure the Unix daemon information */ if (wrapperBuildUnixDaemonInfo()) { return TRUE; } #endif if (_tcscmp(wrapperVersionRoot, getStringProperty(properties, TEXT("wrapper.script.version"), wrapperVersionRoot)) != 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The version of the script (%s) doesn't match the version of this Wrapper (%s). This might cause some problems"), getStringProperty(properties, TEXT("wrapper.script.version"), wrapperVersionRoot), wrapperVersionRoot); } wrapperData->configured = TRUE; return FALSE; } /** * Requests a lock on the tick mutex. * * @return TRUE if there were any problems, FALSE if successful. */ int wrapperLockTickMutex() { #ifdef WIN32 switch (WaitForSingleObject(tickMutexHandle, INFINITE)) { case WAIT_ABANDONED: _tprintf(TEXT("Tick was abandoned.\n")); return TRUE; case WAIT_FAILED: _tprintf(TEXT("Tick wait failed.\n")); return TRUE; case WAIT_TIMEOUT: _tprintf(TEXT("Tick wait timed out.\n")); return TRUE; default: /* Ok */ break; } #else if (pthread_mutex_lock(&tickMutex)) { _tprintf(TEXT("Failed to lock the Tick mutex. %s\n"), getLastErrorText()); return TRUE; } #endif return FALSE; } /** * Releases a lock on the tick mutex. * * @return TRUE if there were any problems, FALSE if successful. */ int wrapperReleaseTickMutex() { #ifdef WIN32 if (!ReleaseMutex(tickMutexHandle)) { _tprintf(TEXT("Failed to release tick mutex. %s\n"), getLastErrorText()); return TRUE; } #else if (pthread_mutex_unlock(&tickMutex)) { _tprintf(TEXT("Failed to unlock the tick mutex. %s\n"), getLastErrorText()); return TRUE; } #endif return FALSE; } /** * Calculates a tick count using the system time. * * We normally need 64 bits to do this calculation. Play some games to get * the correct values with 32 bit variables. */ TICKS wrapperGetSystemTicks() { struct timeb timeBuffer; DWORD high, low; TICKS sum; #ifdef _DEBUG TICKS assertSum; #endif wrapperGetCurrentTime(&timeBuffer); /* Break in half. */ high = (DWORD)(timeBuffer.time >> 16) & 0xffff; low = (DWORD)(timeBuffer.time & 0xffff); /* Work on each half. */ high = high * 1000 / WRAPPER_TICK_MS; low = (low * 1000 + timeBuffer.millitm) / WRAPPER_TICK_MS; /* Now combine them in such a way that the correct bits are truncated. */ high = high + ((low >> 16) & 0xffff); sum = (TICKS)(((high & 0xffff) << 16) + (low & 0xffff)); /* Check the result. */ #ifdef _DEBUG #ifdef WIN32 assertSum = (TICKS)((timeBuffer.time * 1000UI64 + timeBuffer.millitm) / WRAPPER_TICK_MS); #else /* This will produce the following warning on some compilers: * warning: ANSI C forbids long long integer constants * Is there another way to do this? */ assertSum = (TICKS)((timeBuffer.time * 1000ULL + timeBuffer.millitm) / WRAPPER_TICK_MS); #endif if (assertSum != sum) { _tprintf(TEXT("wrapperGetSystemTicks() resulted in %08x rather than %08x\n"), sum, assertSum); } #endif return sum; } /** * Returns difference in seconds between the start and end ticks. This function * handles cases where the tick counter has wrapped between when the start * and end tick counts were taken. See the wrapperGetTicks() function. * * This can be done safely in 32 bits */ int wrapperGetTickAgeSeconds(TICKS start, TICKS end) { /* log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" wrapperGetTickAgeSeconds(%08x, %08x) -> %08x"), start, end, (int)((end - start) * WRAPPER_TICK_MS) / 1000); */ /* Simply subtracting the values will always work even if end has wrapped * due to overflow. * 0x00000001 - 0xffffffff = 0x00000002 = 2 * 0xffffffff - 0x00000001 = 0xfffffffe = -2 */ return (int)((end - start) * WRAPPER_TICK_MS) / 1000; } /** * Returns difference in ticks between the start and end ticks. This function * handles cases where the tick counter has wrapped between when the start * and end tick counts were taken. See the wrapperGetTicks() function. * * This can be done safely in 32 bits */ int wrapperGetTickAgeTicks(TICKS start, TICKS end) { /* log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" wrapperGetTickAgeSeconds(%08x, %08x) -> %08x"), start, end, (int)(end - start)); */ /* Simply subtracting the values will always work even if end has wrapped * due to overflow. * 0x00000001 - 0xffffffff = 0x00000002 = 2 * 0xffffffff - 0x00000001 = 0xfffffffe = -2 */ return (int)(end - start); } /** * Returns TRUE if the specified tick timeout has expired relative to the * specified tick count. */ int wrapperTickExpired(TICKS nowTicks, TICKS timeoutTicks) { /* Convert to a signed value. */ int age = nowTicks - timeoutTicks; if (age >= 0) { return TRUE; } else { return FALSE; } } /** * Returns a tick count that is the specified number of seconds later than * the base tick count. * * This calculation will work as long as the number of seconds is not large * enough to require more than 32 bits when multiplied by 1000. */ TICKS wrapperAddToTicks(TICKS start, int seconds) { /* log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" wrapperAddToTicks(%08x, %08x) -> %08x"), start, seconds, start + (seconds * 1000 / WRAPPER_TICK_MS)); */ return start + (seconds * 1000 / WRAPPER_TICK_MS); } /** * Do some sanity checks on the tick timer math. */ int wrapperTickAssertions() { int result = FALSE; TICKS ticks1, ticks2, ticksR, ticksE; int value1, valueR, valueE; /** wrapperGetTickAgeTicks test. */ ticks1 = 0xfffffffe; ticks2 = 0xffffffff; valueE = 1; valueR = wrapperGetTickAgeTicks(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperGetTickAgeTicks(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } ticks1 = 0xffffffff; ticks2 = 0xfffffffe; valueE = -1; valueR = wrapperGetTickAgeTicks(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperGetTickAgeTicks(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } ticks1 = 0xffffffff; ticks2 = 0x00000000; valueE = 1; valueR = wrapperGetTickAgeTicks(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperGetTickAgeTicks(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } ticks1 = 0x00000000; ticks2 = 0xffffffff; valueE = -1; valueR = wrapperGetTickAgeTicks(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperGetTickAgeTicks(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } /** wrapperGetTickAgeSeconds test. */ ticks1 = 0xfffffff0; ticks2 = 0xffffffff; valueE = 1; valueR = wrapperGetTickAgeSeconds(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperGetTickAgeSeconds(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } ticks1 = 0xffffffff; ticks2 = 0x0000000f; valueE = 1; valueR = wrapperGetTickAgeSeconds(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperGetTickAgeSeconds(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } ticks1 = 0x0000000f; ticks2 = 0xffffffff; valueE = -1; valueR = wrapperGetTickAgeSeconds(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperGetTickAgeSeconds(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } /** wrapperTickExpired test. */ ticks1 = 0xfffffffe; ticks2 = 0xffffffff; valueE = FALSE; valueR = wrapperTickExpired(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperTickExpired(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } ticks1 = 0xffffffff; ticks2 = 0xffffffff; valueE = TRUE; valueR = wrapperTickExpired(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperTickExpired(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } ticks1 = 0xffffffff; ticks2 = 0x00000001; valueE = FALSE; valueR = wrapperTickExpired(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperTickExpired(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } ticks1 = 0x00000001; ticks2 = 0xffffffff; valueE = TRUE; valueR = wrapperTickExpired(ticks1, ticks2); if (valueR != valueE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperTickExpired(%08x, %08x) == %0d != %0d"), ticks1, ticks2, valueR, valueE); result = TRUE; } /** wrapperAddToTicks test. */ ticks1 = 0xffffffff; value1 = 1; ticksE = 0x00000009; ticksR = wrapperAddToTicks(ticks1, value1); if (ticksR != ticksE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Assert Failed: wrapperAddToTicks(%08x, %d) == %08x != %08x"), ticks1, value1, ticksR, ticksE); result = TRUE; } return result; } /** * Sets the working directory of the Wrapper to the specified directory. * The directory can be relative or absolute. * If there are any problems then a non-zero value will be returned. * * @param dir Directory to change to. * @param logErrors TRUE if errors should be logged. */ int wrapperSetWorkingDir(const TCHAR* dir, int logErrors) { int showOutput = wrapperData->configured; if (_tchdir(dir)) { if ( logErrors ) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to set working directory to: %s (%s)"), dir, getLastErrorText()); } return TRUE; } /* This function is sometimes called before the configuration is loaded. */ #ifdef _DEBUG showOutput = TRUE; #endif if (showOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Working directory set to: %s"), dir); } /* Set a variable to the location of the binary. */ setEnv(TEXT("WRAPPER_WORKING_DIR"), dir, ENV_SOURCE_APPLICATION); return FALSE; } /****************************************************************************** * Protocol callback functions *****************************************************************************/ void wrapperLogSignaled(int logLevel, TCHAR *msg) { /* */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Got a log message from JVM: %s"), msg); } /* */ log_printf(wrapperData->jvmRestarts, logLevel, msg); } void wrapperKeyRegistered(TCHAR *key) { /* Allow for a large integer + \0 */ TCHAR buffer[11]; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Got key from JVM: %s"), key); } switch (wrapperData->jState) { case WRAPPER_JSTATE_LAUNCHING: /* We now know that the Java side wrapper code has started and * registered with a key. We still need to verify that it is * the correct key however. */ if (_tcscmp(key, wrapperData->key) == 0) { /* This is the correct key. */ /* We now know that the Java side wrapper code has started. */ wrapperSetJavaState(WRAPPER_JSTATE_LAUNCHED, 0, -1); /* Send the low log level to the JVM so that it can control output via the log method. */ _sntprintf(buffer, 11, TEXT("%d"), getLowLogLevel()); wrapperProtocolFunction(WRAPPER_MSG_LOW_LOG_LEVEL, buffer); /* Send the log file name. */ sendLogFileName(); /* Send the properties. */ sendProperties(); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Received a connection request with an incorrect key. Waiting for another connection.")); /* This was the wrong key. Send a response. */ wrapperProtocolFunction(WRAPPER_MSG_BADKEY, TEXT("Incorrect key. Connection rejected.")); /* Close the current connection. Assume that the real JVM * is still out there trying to connect. So don't change * the state. If for some reason, this was the correct * JVM, but the key was wrong. then this state will time * out and recover. */ wrapperProtocolClose(); } break; case WRAPPER_JSTATE_STOP: /* We got a key registration. This means that the JVM thinks it was * being launched but the Wrapper is trying to stop. This state * will clean up correctly. */ break; case WRAPPER_JSTATE_STOPPING: /* We got a key registration. This means that the JVM thinks it was * being launched but the Wrapper is trying to stop. Now that the * connection to the JVM has been opened, tell it to stop cleanly. */ wrapperSetJavaState(WRAPPER_JSTATE_STOP, 0, -1); break; default: /* We got a key registration that we were not expecting. Ignore it. */ break; } } /** * Called when a ping is first determined to be slower than the wrapper.ping.alert.threshold. * This will happen before it has actually been responded to. */ void wrapperPingSlow() { } /** * Called when a ping is responded to, but was slower than the wrapper.ping.alert.threshold. * * @param tickAge The number of seconds it took to respond. */ void wrapperPingRespondedSlow(int tickAge) { log_printf(WRAPPER_SOURCE_WRAPPER, wrapperData->pingAlertLogLevel, TEXT("Pinging the JVM took %d seconds to respond."), tickAge); } /** * Called when a ping response is received. * * @param pingSendTicks Time in ticks when the ping was originally sent. * @param queueWarnings TRUE if warnings about the queue should be logged, FALSE if the ping response did not contain a time. */ void wrapperPingResponded(TICKS pingSendTicks, int queueWarnings) { TICKS nowTicks; int tickAge; PPendingPing pendingPing; int pingSearchDone; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE Ping Response (tick %08x)"), pingSendTicks); #endif /* We want to purge the ping from the PendingPing list. */ do { pendingPing = wrapperData->firstPendingPing; if (pendingPing != NULL) { tickAge = wrapperGetTickAgeTicks(pingSendTicks, pendingPing->sentTicks); #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE First Queued Ping (tick %08x, age %d)"), pendingPing->sentTicks, tickAge); #endif if (tickAge > 0) { /* pendingPing->sentTicks > pingSendTicks */ /* We received a ping response that is earlier than the one we were expecting. * If the pendingPingQueue has overflown then we will stop writing to it. Don't long warning messages when in this state as they would be confusing and are expected. * Leave this one in the queue for later. */ if (queueWarnings) { if ((!wrapperData->pendingPingQueueOverflow) && (!wrapperData->pendingPingQueueOverflowEmptied)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Received an unexpected ping response, sent at tick %08x. First expected ping was sent at tick %08x."), pingSendTicks, pendingPing->sentTicks); } else { #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE Silently skipping unexpected ping response. (tick %08x) (First tick %08x)"), pingSendTicks, pendingPing->sentTicks); #endif } } pendingPing = NULL; pingSearchDone = TRUE; } else { if (tickAge < 0) { /* This PendingPing object was sent before the PING that we received. This means that we somehow lost a ping. */ if (queueWarnings) { if ((!wrapperData->pendingPingQueueOverflow) && (!wrapperData->pendingPingQueueOverflowEmptied)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Lost a ping response, sent at tick %08x."), pendingPing->sentTicks); } else { #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE Silently skipping lost ping response. (tick %08x)"), pendingPing->sentTicks); #endif } } pingSearchDone = FALSE; } else { /* This PendingPing object is for this PING event. */ pingSearchDone = TRUE; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE Expected Ping Response. (tick %08x)"), pendingPing->sentTicks); #endif /* When the emptied flag is set, we know that we are recovering from an overflow. * That flag is reset on the first expected PendingPing found in the queue. */ if (wrapperData->pendingPingQueueOverflowEmptied) { wrapperData->pendingPingQueueOverflowEmptied = FALSE; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE Emptied Set flag reset.")); #endif } } /* Detach the PendingPing from the queue. */ if (pendingPing->nextPendingPing != NULL) { /* This was the first PendingPing of several in the queue. */ wrapperData->pendingPingCount--; if (wrapperData->firstUnwarnedPendingPing == wrapperData->firstPendingPing) { wrapperData->firstUnwarnedPendingPing = pendingPing->nextPendingPing; } wrapperData->firstPendingPing = pendingPing->nextPendingPing; pendingPing->nextPendingPing = NULL; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("--- PING QUEUE Size: %d"), wrapperData->pendingPingCount); #endif } else { /* This was the only PendingPing in the queue. */ wrapperData->pendingPingCount = 0; wrapperData->firstUnwarnedPendingPing = NULL; wrapperData->firstPendingPing = NULL; wrapperData->lastPendingPing = NULL; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("--- PING QUEUE Empty.") ); #endif if (wrapperData->pendingPingQueueOverflow) { wrapperData->pendingPingQueueOverflowEmptied = TRUE; wrapperData->pendingPingQueueOverflow = FALSE; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE Reset Overflow, Emptied Set.") ); #endif } } /* Free up the pendingPing object. */ if (pendingPing != NULL) { free(pendingPing); pendingPing = NULL; } } } else { /* Got a ping response when the queue was empty. */ if (queueWarnings) { if ((!wrapperData->pendingPingQueueOverflow) && (!wrapperData->pendingPingQueueOverflowEmptied)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Received an unexpected ping response, sent at tick %08x."), pingSendTicks); } else { #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE Silently skipping unexpected ping response. (tick %08x) (Empty)"), pingSendTicks); #endif } } pingSearchDone = TRUE; } } while (!pingSearchDone); /* Depending on the current JVM state, do something. */ switch (wrapperData->jState) { case WRAPPER_JSTATE_STARTED: /* We got a response to a ping. */ nowTicks = wrapperGetTicks(); /* Figure out how long it took for us to get this ping response in seconds. */ tickAge = wrapperGetTickAgeSeconds(pingSendTicks, nowTicks); /* If we took longer than the threshold then we want to log a message. */ if ((wrapperData->pingAlertThreshold > 0) && (tickAge >= wrapperData->pingAlertThreshold)) { wrapperPingRespondedSlow(tickAge); } /* Allow 5 + more seconds before the JVM is considered to be dead. */ if (wrapperData->pingTimeout > 0) { wrapperUpdateJavaStateTimeout(nowTicks, 5 + wrapperData->pingTimeout); } else { wrapperUpdateJavaStateTimeout(nowTicks, -1); } break; default: /* We got a ping response that we were not expecting. Ignore it. */ break; } } void wrapperPingTimeoutResponded() { wrapperProcessActionList(wrapperData->pingActionList, TEXT("JVM appears hung: Timed out waiting for signal from JVM."), WRAPPER_ACTION_SOURCE_CODE_PING_TIMEOUT, TRUE, 1); } void wrapperStopRequested(int exitCode) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM requested a shutdown. (%d)"), exitCode); } /* Get things stopping on this end. Ask the JVM to stop again in case the * user code on the Java side is not written correctly. */ wrapperStopProcess(exitCode, FALSE); } void wrapperRestartRequested() { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JVM requested a restart.")); /* Make a note of the fact that we received this restart packet. */ wrapperData->restartPacketReceived = TRUE; wrapperRestartProcess(); } /** * If the current state of the JVM is STOPPING then this message is used to * extend the time that the wrapper will wait for a STOPPED message before * giving up on the JVM and killing it. */ void wrapperStopPendingSignaled(int waitHint) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM signaled a stop pending with waitHint of %d millis."), waitHint); } if (wrapperData->jState == WRAPPER_JSTATE_STARTED) { /* Change the state to STOPPING */ wrapperSetJavaState(WRAPPER_JSTATE_STOPPING, 0, -1); /* Don't need to set the timeout here because it will be set below. */ } if (wrapperData->jState == WRAPPER_JSTATE_STOPPING) { if (waitHint < 0) { waitHint = 0; } wrapperUpdateJavaStateTimeout(wrapperGetTicks(), (int)ceil(waitHint / 1000.0)); } } /** * The wrapper received a signal from the JVM that it has completed the stop * process. If the state of the JVM is STOPPING, then change the state to * STOPPED. It is possible to get this request after the Wrapper has given up * waiting for the JVM. In this case, the message is ignored. */ void wrapperStoppedSignaled() { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM signaled that it was stopped.")); } /* If the restart mode is already set and it is WRAPPER_RESTART_REQUESTED_AUTOMATIC but we * have not yet received a RESTART packet, this means that state engine got confused because * of an unexpected delay. The fact that the STOPPED packet arived but not the RESTART packet * means that the application did not intend for the restart to take place. * Reset the restart and let the Wrapper exit. */ if ((wrapperData->restartRequested == WRAPPER_RESTART_REQUESTED_AUTOMATIC) && (!wrapperData->restartPacketReceived)) { /* If we get here it is because the Wrapper previously decided to do a restart to recover. * That means that another message was already shown to the user. We want to show another * message here so there is a record of why we don't restart. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Received Stopped packet late. Cancel automatic restart.")); wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_NO; } /* Make a note of the fact that we received this stopped packet. */ wrapperData->stoppedPacketReceived = TRUE; if ((wrapperData->jState == WRAPPER_JSTATE_STARTING) || (wrapperData->jState == WRAPPER_JSTATE_STARTED) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING)) { /* The Java side of the wrapper signaled that it stopped * allow 5 + jvmExitTimeout seconds for the JVM to exit. */ if (wrapperData->jvmExitTimeout > 0) { wrapperSetJavaState(WRAPPER_JSTATE_STOPPED, wrapperGetTicks(), 5 + wrapperData->jvmExitTimeout); } else { wrapperSetJavaState(WRAPPER_JSTATE_STOPPED, 0, -1); } } } /** * If the current state of the JVM is STARTING then this message is used to * extend the time that the wrapper will wait for a STARTED message before * giving up on the JVM and killing it. */ void wrapperStartPendingSignaled(int waitHint) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM signaled a start pending with waitHint of %d millis."), waitHint); } /* Only process the start pending signal if the JVM state is starting or * stopping. Stopping are included because if the user hits CTRL-C while * the application is starting, then the stop request will not be noticed * until the application has completed its startup. */ if ((wrapperData->jState == WRAPPER_JSTATE_STARTING) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING)) { if (waitHint < 0) { waitHint = 0; } wrapperUpdateJavaStateTimeout(wrapperGetTicks(), (int)ceil(waitHint / 1000.0)); } } /** * The wrapper received a signal from the JVM that it has completed the startup * process. If the state of the JVM is STARTING, then change the state to * STARTED. It is possible to get this request after the Wrapper has given up * waiting for the JVM. In this case, the message is ignored. */ void wrapperStartedSignaled() { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM signaled that it was started.")); } if (wrapperData->jState == WRAPPER_JSTATE_STARTING) { /* We got the expected started packed. Now start pinging. Allow 5 + more seconds before the JVM * is considered to be dead. */ if (wrapperData->pingTimeout > 0) { wrapperSetJavaState(WRAPPER_JSTATE_STARTED, wrapperGetTicks(), 5 + wrapperData->pingTimeout); } else { wrapperSetJavaState(WRAPPER_JSTATE_STARTED, 0, -1); } /* Is the wrapper state STARTING? */ if (wrapperData->wState == WRAPPER_WSTATE_STARTING) { wrapperSetWrapperState(WRAPPER_WSTATE_STARTED); if (!wrapperData->isConsole) { /* Tell the service manager that we started */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_STARTED, 0, 0); } } /* If we are configured to detach and shutdown when the JVM is started then start doing so. */ if (wrapperData->detachStarted) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JVM launched and detached. Wrapper Shutting down...")); wrapperProtocolClose(); wrapperDetachJava(); wrapperStopProcess(0, FALSE); } } else if (wrapperData->jState == WRAPPER_JSTATE_STOP) { /* This will happen if the Wrapper was asked to stop as the JVM is being launched. */ } else if (wrapperData->jState == WRAPPER_JSTATE_STOPPING) { /* This will happen if the Wrapper was asked to stop as the JVM is being launched. */ wrapperSetJavaState(WRAPPER_JSTATE_STOP, 0, -1); } } #ifdef CUNIT static void tsJAP_subTestJavaAdditionalParamSuite(int stripQuote, TCHAR *config, TCHAR **strings, int strings_len, int isJVMParam) { LoadParameterFileCallbackParam param; int ret; /*int i;*/ param.stripQuote = stripQuote; param.strings = NULL; param.index = 0; param.isJVMParam = isJVMParam; ret = loadParameterFileCallback((void *)(¶m), NULL, 0, config, FALSE); CU_ASSERT_TRUE(ret); if (!ret) { return; } CU_ASSERT(strings_len == param.index); param.stripQuote = stripQuote; param.strings = (TCHAR **)malloc(sizeof(TCHAR *) * strings_len); if (!param.strings) { return; } param.index = 0; param.isJVMParam = isJVMParam; ret = loadParameterFileCallback((void *)(¶m), NULL, 0, config, FALSE); CU_ASSERT_TRUE(ret); if (!ret) { return; } CU_ASSERT(strings_len == param.index); if (!param.strings) { return; } /*for (i = 0; i < strings_len; i++) { CU_ASSERT(_tcscmp(strings[i], param.strings[i]) == 0); }*/ /*for (i = 0; i < strings_len; i++) { free(param.strings[i]); }*/ free(param.strings); } #define TSJAP_ARRAY_LENGTH(a) (sizeof(a) / sizeof(a[0])) void tsJAP_testJavaAdditionalParamSuite(void) { int stripQuote; int i = 0; int isJVM = TRUE; for (i = 0; i < 2; i++) { _tprintf(TEXT("%d round\n"), i); if (i > 0) { isJVM = FALSE; } /* Test set #1 */ { /* Single parameter in 1 line. */ TCHAR *config = TEXT("-Dsomething=something"); TCHAR *strings[1]; strings[0] = TEXT("-Dsomething=something"); tsJAP_subTestJavaAdditionalParamSuite(FALSE, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Multiple parameters in 1 line. */ TCHAR *config = TEXT("-Dsomething=something -Dxxx=xxx"); TCHAR *strings[2]; strings[0] = TEXT("-Dsomething=something"); strings[1] = TEXT("-Dxxx=xxx"); tsJAP_subTestJavaAdditionalParamSuite(FALSE, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Horizontal Tab is not a delimiter. */ TCHAR *config = TEXT("-Dsomething1=something1\t-Dsomething2=something2 -Dxxx=xxx"); TCHAR *strings[2]; strings[0] = TEXT("-Dsomething1=something1\t-Dsomething2=something2"); strings[1] = TEXT("-Dxxx=xxx"); tsJAP_subTestJavaAdditionalParamSuite(FALSE, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Horizontal Tab is not a delimiter. */ TCHAR *config = TEXT("-Dsomething1=something1\t-Dsomething2=something2 -Dxxx=xxx"); TCHAR *strings[2]; strings[0] = TEXT("-Dsomething1=something1\t-Dsomething2=something2"); strings[1] = TEXT("-Dxxx=xxx"); tsJAP_subTestJavaAdditionalParamSuite(FALSE, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } if (isJVM == TRUE) { { /* A parameter without heading '-' will be skipped. */ TCHAR *config = TEXT("something=something -Dxxx=xxx"); TCHAR *strings[1]; strings[0] = TEXT("-Dxxx=xxx"); tsJAP_subTestJavaAdditionalParamSuite(FALSE, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } } else { { /* A parameter without heading '-' will not be skipped. */ TCHAR *config = TEXT("something=something -Dxxx=xxx"); TCHAR *strings[2]; strings[0] = TEXT("something=something"); strings[1] = TEXT("-Dxxx=xxx"); tsJAP_subTestJavaAdditionalParamSuite(FALSE, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } } /* Test set #2 : without stripping double quotations */ stripQuote = FALSE; { /* Quotations #1 */ TCHAR *config = TEXT("-DmyApp.x1=\"Hello World.\" -DmyApp.x2=x2"); TCHAR *strings[2]; strings[0] = TEXT("-DmyApp.x1=\"Hello World.\""); strings[1] = TEXT("-DmyApp.x2=x2"); tsJAP_subTestJavaAdditionalParamSuite(stripQuote, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Quotations #2 */ TCHAR *config = TEXT("\"-DmyApp.x1=Hello World.\" -DmyApp.x2=x2"); TCHAR *strings[2]; strings[0] = TEXT("\"-DmyApp.x1=Hello World.\""); strings[1] = TEXT("-DmyApp.x2=x2"); tsJAP_subTestJavaAdditionalParamSuite(stripQuote, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Escaped quotation */ TCHAR *config = TEXT("-DmyApp.x1=\"Hello \\\"World.\" -DmyApp.x2=x2"); TCHAR *strings[2]; strings[0] = TEXT("-DmyApp.x1=\"Hello \\\"World.\""); strings[1] = TEXT("-DmyApp.x2=x2"); tsJAP_subTestJavaAdditionalParamSuite(stripQuote, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Escaped backslash */ TCHAR *config = TEXT("-DmyApp.x1=\"Hello World.\\\\\" -DmyApp.x2=x2"); TCHAR *strings[2]; strings[0] = TEXT("-DmyApp.x1=\"Hello World.\\\\\""); strings[1] = TEXT("-DmyApp.x2=x2"); tsJAP_subTestJavaAdditionalParamSuite(stripQuote, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } /* Test set #3 : with stripping double quotations */ stripQuote = TRUE; { /* Quotations #1 */ TCHAR *config = TEXT("-DmyApp.x1=\"Hello World.\" -DmyApp.x2=x2"); TCHAR *strings[2]; strings[0] = TEXT("-DmyApp.x1=Hello World."); strings[1] = TEXT("-DmyApp.x2=x2"); tsJAP_subTestJavaAdditionalParamSuite(stripQuote, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Quotations #2 */ TCHAR *config = TEXT("\"-DmyApp.x1=Hello World.\" -DmyApp.x2=x2"); TCHAR *strings[2]; strings[0] = TEXT("-DmyApp.x1=Hello World."); strings[1] = TEXT("-DmyApp.x2=x2"); tsJAP_subTestJavaAdditionalParamSuite(stripQuote, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Escaped quotation */ TCHAR *config = TEXT("-DmyApp.x1=\"Hello \\\"World.\" -DmyApp.x2=x2"); TCHAR *strings[2]; strings[0] = TEXT("-DmyApp.x1=Hello \"World."); strings[1] = TEXT("-DmyApp.x2=x2"); tsJAP_subTestJavaAdditionalParamSuite(stripQuote, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } { /* Escaped backslash */ TCHAR *config = TEXT("-DmyApp.x1=\"Hello World.\\\\\" -DmyApp.x2=x2"); TCHAR *strings[2]; strings[0] = TEXT("-DmyApp.x1=Hello World.\\"); strings[1] = TEXT("-DmyApp.x2=x2"); tsJAP_subTestJavaAdditionalParamSuite(stripQuote, config, strings, TSJAP_ARRAY_LENGTH(strings), isJVM); } } } #endif /* CUNIT */ wrapper_3.5.26_src/src/c/wrapper.h100644 0 0 150541 12440202301 14243 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ #ifndef _WRAPPER_H #define _WRAPPER_H #ifdef WIN32 #include #endif #include #ifdef WIN32 #include #else /* UNIX */ #include #include #include #ifndef MACOSX #define u_short unsigned short #endif /* MACOSX */ #endif #ifndef DWORD #define DWORD unsigned long #endif #include #include "property.h" #ifndef WIN32 /* * Mac OSX 10.5 does not define the environ variable. This is work around for that. */ #ifdef MACOSX #include #define environ *_NSGetEnviron(); #endif extern char** environ; #endif /* The following define will enable debug output of the code to parse the JVM output. */ /*#define DEBUG_CHILD_OUTPUT*/ /* Initialize the timerTicks to a very high value. This means that we will * always encounter the first rollover (512 * WRAPPER_MS / 1000) seconds * after the Wrapper the starts, which means the rollover will be well * tested. */ #define WRAPPER_TICK_INITIAL 0xfffffe00 #define WRAPPER_TICK_MS 100 /* The number of ms that are represented by a single * tick. Ticks are used as an alternative time * keeping method. See the wrapperGetTicks() and * wrapperGetTickAgeSeconds() functions for more information. * Some code assumes that this number can be evenly * divided into 1000. */ #define WRAPPER_MAX_UPTIME_SECONDS 365 * 24 * 3600 /* Maximum uptime count. 1 year. */ #define WRAPPER_MAX_UPTIME_TICKS (WRAPPER_MAX_UPTIME_SECONDS * (1000 / WRAPPER_TICK_MS)) /* The paranthesis are important to avoid overflow. */ #define WRAPPER_TIMER_FAST_THRESHOLD (2 * 24 * 3600 * 1000 / WRAPPER_TICK_MS) /* Default to 2 days. */ #define WRAPPER_TIMER_SLOW_THRESHOLD (2 * 24 * 3600 * 1000 / WRAPPER_TICK_MS) /* Default to 2 days. */ #define WRAPPER_BACKEND_ERROR_NEXT 99 /* value returned when there is an error trying to connect to a socket and we should try the next way to connect */ #define WRAPPER_BACKEND_TYPE_UNKNOWN 0 /* Unknown type. */ #define WRAPPER_BACKEND_TYPE_SOCKET_V4 0x01 #define WRAPPER_BACKEND_TYPE_SOCKET_V6 0x02 #define WRAPPER_BACKEND_TYPE_SOCKET (WRAPPER_BACKEND_TYPE_SOCKET_V4 | WRAPPER_BACKEND_TYPE_SOCKET_V6) #define WRAPPER_BACKEND_TYPE_PIPE 0x04 /* Use a pair of pipes to communicate. */ #define WRAPPER_BACKEND_TYPE_AUTO (WRAPPER_BACKEND_TYPE_SOCKET | WRAPPER_BACKEND_TYPE_PIPE) #define WRAPPER_WSTATE_STARTING 51 /* Wrapper is starting. Remains in this state * until the JVM enters the STARTED state or * the wrapper jumps into the STOPPING state * in response to the JVM application asking * to shut down. */ #define WRAPPER_WSTATE_STARTED 52 /* The JVM has entered the STARTED state. * The wrapper will remain in this state * until the wrapper decides to shut down. * This is true even when the JVM process * is being restarted. */ #define WRAPPER_WSTATE_PAUSING 53 /* The wrapper enters this state when asked to Pause. */ #define WRAPPER_WSTATE_PAUSED 54 /* The wrapper enters this state when the Wrapper * has actually paused. */ #define WRAPPER_WSTATE_RESUMING 55 /* The wrapper enters this state when asked to Resume. */ #define WRAPPER_WSTATE_STOPPING 56 /* The wrapper is shutting down. Will be in * this state until the JVM enters the DOWN * state. */ #define WRAPPER_WSTATE_STOPPED 57 /* The wrapper enters this state just before * it exits. */ #define WRAPPER_JSTATE_DOWN_CHECK 70 /* JVM is confirmed to be down, but we still need * to do our cleanup work. This is the state after * a JVM process has gone away. */ #define WRAPPER_JSTATE_DOWN_FLUSH 71 /* JVM is confirmed to be down but we still need * flush and process all of its output. */ #define WRAPPER_JSTATE_DOWN_CLEAN 72 /* JVM is confirmed to be down and we have cleaned * up and flushed all output. This is the initial * state and the state after the JVM process has * gone away and and cleanup has been done. */ #define WRAPPER_JSTATE_LAUNCH_DELAY 73 /* Set from the DOWN state to launch a JVM. The * timeout will be the time to actually launch * the JVM after any required delay. */ #define WRAPPER_JSTATE_RESTART 74 /* JVM is about to be restarted. No timeout. */ #define WRAPPER_JSTATE_LAUNCH 75 /* JVM is about to launch a JVM. No timeout. */ #define WRAPPER_JSTATE_LAUNCHING 76 /* JVM was launched, but has not yet responded. * Must enter the LAUNCHED state before * or the JVM will be killed. */ #define WRAPPER_JSTATE_LAUNCHED 77 /* JVM was launched, and responed to a ping. */ #define WRAPPER_JSTATE_STARTING 78 /* JVM has been asked to start. Must enter the * STARTED state before or the JVM will be * killed. */ #define WRAPPER_JSTATE_STARTED 79 /* JVM has responded that it is running. Must * respond to a ping by or the JVM will * be killed. */ #define WRAPPER_JSTATE_STOP 80 /* JVM is about to be sent a stop command to shutdown * cleanly. */ #define WRAPPER_JSTATE_STOPPING 81 /* JVM was sent a stop command, but has not yet * responded. Must enter the STOPPED state * and exit before or the JVM will be killed. */ #define WRAPPER_JSTATE_STOPPED 82 /* JVM has responed that it is stopped. */ #define WRAPPER_JSTATE_KILLING 83 /* The Wrapper is about ready to kill the JVM * process but it must wait a few moments before * actually doing so. After has expired, the * JVM will be killed and we will enter the STOPPED * state. */ #define WRAPPER_JSTATE_KILL 84 /* The Wrapper is about ready to kill the JVM process. */ #define WRAPPER_JSTATE_KILLED 85 /* The Wrapper has requested termination of the JVM and confirmed the JVM is actually killed */ /* Defined Action types. Registered actions are negative. Custom types are positive. */ #define ACTION_LIST_END 0 #define ACTION_NONE -1 #define ACTION_RESTART -2 #define ACTION_SHUTDOWN -3 #define ACTION_DUMP -4 #define ACTION_DEBUG -5 #define ACTION_PAUSE -6 #define ACTION_RESUME -7 #define ACTION_SUCCESS -8 #define ACTION_GC -9 #if defined(MACOSX) #define TRIGGER_ADVICE_NIL_SERVER TEXT("****** Returning nil _server **********") #define ACTION_ADVICE_NIL_SERVER -32 #endif /* The following codes are passed through and referenced within the WrapperServiceActionEvent class. * They can be added, but not changed without the possibility of affecting user code. */ #define WRAPPER_ACTION_SOURCE_CODE_FILTER 1 /* Action originated with a filter. */ #define WRAPPER_ACTION_SOURCE_CODE_COMMANDFILE 2 /* Action originated from a commandfile. */ #define WRAPPER_ACTION_SOURCE_CODE_WINDOWS_SERVICE_MANAGER 3 /* Action originated from the Windows Service Manager. */ #define WRAPPER_ACTION_SOURCE_CODE_ON_EXIT 4 /* Action originated from an on_exit configuration. */ #define WRAPPER_ACTION_SOURCE_CODE_PING_TIMEOUT 11 /* Action originated from a timeout. */ /* Because of the way time is converted to ticks, the largest possible timeout that * can be specified without causing 32-bit overflows is (2^31 / 1000) - 5 = 2147478 * Which is a little over 24 days. To make the interface nice, round this down to * 20 days. Or 1728000. */ #define WRAPPER_TIMEOUT_MAX 1728000 #define WRAPPER_IGNORE_SIGNALS_WRAPPER 1 #define WRAPPER_IGNORE_SIGNALS_JAVA 2 #define WRAPPER_RESTART_REQUESTED_NO 0 #define WRAPPER_RESTART_REQUESTED_INITIAL 1 #define WRAPPER_RESTART_REQUESTED_AUTOMATIC 2 #define WRAPPER_RESTART_REQUESTED_CONFIGURED 4 #ifdef JSW64 typedef unsigned int TICKS; #else typedef unsigned long TICKS; #endif #ifdef WIN32 /* Defines the maximum number of service manager control events that can be queued in a single loop. */ #define CTRL_CODE_QUEUE_SIZE 26 /* Can enqueue one less than this count at any time. */ #endif #define WRAPPER_JAVAIO_BUFFER_SIZE_SYSTEM_DEFAULT 0 #define WRAPPER_JAVAIO_BUFFER_SIZE_MIN 1024 #define WRAPPER_JAVAIO_BUFFER_SIZE_MAX (10 * 1024 * 1024) #define WRAPPER_JAVAIO_BUFFER_SIZE_DEFAULT (64 * 1024) /*#define DEBUG_PING_QUEUE*/ #define WRAPPER_MAX_PENDING_PINGS 10 typedef struct PendingPing PendingPing, *PPendingPing; struct PendingPing { TICKS sentTicks; TICKS timeoutTicks; TICKS slowTicks; PPendingPing nextPendingPing; }; /* Type definitions */ typedef struct WrapperConfig WrapperConfig; struct WrapperConfig { TCHAR *argBinary; /* The name of the wrapper binary. */ TCHAR *argCommand; /* The command used to launch the wrapper. */ TCHAR *argCommandArg; /* The argument to the command used to launch the wrapper. */ TCHAR *argConfFile; /* The name of the config file from the command line. */ TCHAR *confDir; int argConfFileDefault; /* True if the config file was not specified. */ int argConfFileFound; /* True if the config file was found. */ int argCount; /* The total argument count. */ TCHAR **argValues; /* Argument values. */ TCHAR **javaArgValues; /* Arguments getting passed over to the java application */ int javaArgValueCount; /* Number of the arguments getting passed over to the java application */ TCHAR *initialPath; /* What the working directory was when the Wrapper process was first launched. */ TCHAR *language; /* The language */ int backendType; /* The type of the backend that the Wrapper and Java use to communicate. */ int configured; /* TRUE if loadConfiguration has been called. */ int useSystemTime; /* TRUE if the wrapper should use the system clock for timing, FALSE if a tick counter should be used. */ int logBufferGrowth; /* TRUE if changes to internal buffer sizes should be logged. */ int timerFastThreshold; /* If the difference between the system time based tick count and the timer tick count ever falls by more than this value then a warning will be displayed. */ int timerSlowThreshold; /* If the difference between the system time based tick count and the timer tick count ever grows by more than this value then a warning will be displayed. */ int useTickMutex; /* TRUE if access to the tick count should be protected by a mutex. */ int uptimeFlipped; /* TRUE when the maximum uptime has been flipped. (Overflown) */ int ignoreSequenceGaps; /* TRUE if all sequence properties should be used. */ int port; /* Port number which the Wrapper is configured to be listening on */ int portMin; /* Minimum port to use when looking for a port to bind to. */ int portMax; /* Maximum port to use when looking for a port to bind to. */ int actualPort; /* Port number which the Wrapper is actually listening on */ int jvmPort; /* The port which the JVM should bind to when connecting back to the wrapper. */ int jvmPortMin; /* Minimum port which the JVM should bind to when connecting back to the wrapper. */ int jvmPortMax; /* Maximum port which the JVM should bind to when connecting back to the wrapper. */ int sock; /* Socket number. if open. */ TCHAR *portAddress; TCHAR *originalWorkingDir; /* Original Wrapper working directory. */ TCHAR *workingDir; /* Configured working directory. */ TCHAR *configFile; /* Name of the configuration file */ int commandLogLevel; /* The log level to use when logging the java command. */ int printJVMVersion; /* tells the Wrapper to create a temp JVM to query the version, before starting the java application */ #ifdef WIN32 TCHAR *jvmVersionCommand; /* Command used to launch the JVM and request its version */ TCHAR *jvmCommand; /* Command used to launch the JVM */ #else /* UNIX */ TCHAR **jvmVersionCommand; /* Command used to launch the JVM and request its version */ TCHAR **jvmCommand; /* Command used to launch the JVM */ #endif int detachStarted; /* TRUE if the JVM process should be detached once it has started. */ int environmentClasspath; /* TRUE if the classpath should be passed to the JVM in the environment. */ TCHAR *classpath; /* Classpath to pass to the JVM. */ int debugJVM; /* True if the JVM is being launched with a debugger enabled. */ int debugJVMTimeoutNotified;/* True if the JVM is being launched with a debugger enabled and the user has already been notified of a timeout. */ TCHAR key[17]; /* Key which the JVM uses to authorize connections. (16 digits + \0) */ int isConsole; /* TRUE if the wrapper was launched as a console. */ int cpuTimeout; /* Number of seconds without CPU before the JVM will issue a warning and extend timeouts */ int startupTimeout; /* Number of seconds the wrapper will wait for a JVM to startup */ int pingTimeout; /* Number of seconds the wrapper will wait for a JVM to reply to a ping */ int pingAlertThreshold; /* Number of seconds without a ping response that the Wrapper will start to warn about a slow ping. */ int pingAlertLogLevel; /* Long level at which slow ping notices are logged. */ int pingInterval; /* Number of seconds between pinging the JVM */ int pingIntervalLogged; /* Number of seconds between pings which can be logged to debug output. */ int *pingActionList; /* The action list to take when a ping timeout is detected. */ int pingTimedOut; int shutdownTimeout; /* Number of seconds the wrapper will wait for a JVM to shutdown */ int jvmExitTimeout; /* Number of seconds the wrapper will wait for a JVM to process to terminate */ int jvmCleanupTimeout; /* Number of seconds the wrapper will allow for its post JVM shudown cleanup. */ int jvmTerminateTimeout; /* Number of seconds the wrapper will allow for the JVM to respond to TerminateProcess request. */ #ifdef WIN32 int javaIOBufferSize; /* Size of the pipe buffer to use for java I/O. */ #endif int useJavaIOThread; /* If TRUE then a dedicated thread will be used to process console output form the JVM. */ int pauseThreadMain; /* Number of seconds to pause the main thread on its next loop. Only used for testing. */ int pauseThreadTimer; /* Number of seconds to pause the timer thread on its next loop. Only used for testing. */ int pauseThreadJavaIO; /* Number of seconds to pause the javaio thread on its next loop. Only used for testing. */ #ifdef WIN32 int ignoreUserLogoffs; /* If TRUE, the Wrapper will ignore logoff events when run in the background as an in console mode. */ TCHAR *userName; /* The username (account) of the Wrapper process. */ TCHAR *domainName; /* The domain of the Wrapper process. */ DWORD wrapperPID; /* PID of the Wrapper process. */ DWORD javaPID; /* PID of the Java process. */ HANDLE wrapperProcess; /* Handle of the Wrapper process. */ HANDLE javaProcess; /* Handle of the Java process. */ #else pid_t wrapperPID; /* PID of the Wrapper process. */ pid_t javaPID; /* PID of the Java process. */ #endif int wState; /* The current state of the wrapper */ int jState; /* The current state of the jvm */ TICKS jStateTimeoutTicks; /* Tick count until which the current jState is valid */ int jStateTimeoutTicksSet; /* 1 if the current jStateTimeoutTicks is set. */ TICKS lastPingTicks; /* Time that the last ping was sent */ TICKS lastLoggedPingTicks; /* Time that the last logged ping was sent */ int isDebugging; /* TRUE if set in the configuration file */ int isAdviserEnabled; /* TRUE if advice messages should be output. */ const TCHAR *nativeLibrary; /* The base name of the native library loaded by the WrapperManager. */ int libraryPathAppendPath; /* TRUE if the PATH environment variable should be appended to the java library path. */ int isStateOutputEnabled; /* TRUE if set in the configuration file. Shows output on the state of the state engine. */ int isJavaIOOutputEnabled; /* TRUE if detailed javaIO output should be included in debug output. */ int isTickOutputEnabled; /* TRUE if detailed tick timer output should be included in debug output. */ int isLoopOutputEnabled; /* TRUE if very detailed output from the main loop should be output. */ int isSleepOutputEnabled; /* TRUE if detailed sleep output should be included in debug output. */ int isMemoryOutputEnabled; /* TRUE if detailed memory output should be included in status output. */ int memoryOutputInterval; /* Interval in seconds at which memory usage is logged. */ TICKS memoryOutputTimeoutTicks; /* Tick count at which memory will next be logged. */ int isCPUOutputEnabled; /* TRUE if detailed CPU output should be included in status output. */ int cpuOutputInterval; /* Interval in seconds at which CPU usage is logged. */ TICKS cpuOutputTimeoutTicks; /* Tick count at which CPU will next be logged. */ int isPageFaultOutputEnabled;/* TRUE if detailed PageFault output should be included in status output. */ int pageFaultOutputInterval;/* Interval in seconds at which PageFault usage is logged. */ TICKS pageFaultOutputTimeoutTicks; /* Tick count at which PageFault will next be logged. */ int logfileFlushTimeout; /* The number of seconds before the logfile will be flushed. */ TICKS logfileFlushTimeoutTicks; /* Tick count at which the logfile will be flushed. */ int logfileFlushTimeoutTicksSet; /* TRUE if logfileFlushTimeoutTicks is set. */ int logfileCloseTimeout; /* The number of seconds of inactivity before the logfile will be closed. */ TICKS logfileCloseTimeoutTicks; /* Tick count at which the logfile will be considered inactive and closed. */ int logfileCloseTimeoutTicksSet; /* TRUE if logfileCloseTimeoutTicks is set. */ int isTestsDisabled; /* TRUE if the use of tests in the WrapperManager class should be disabled. */ int isShutdownHookDisabled; /* TRUE if the use of a shutdown hook by the WrapperManager class should be disabled. */ int isForcedShutdownDisabled; /* TRUE if forced shutdowns are disabled. */ int startupDelayConsole; /* Delay in seconds before starting the first JVM in console mode. */ int startupDelayService; /* Delay in seconds before starting the first JVM in service mode. */ int exitCode; /* Code which the wrapper will exit with */ int exitRequested; /* TRUE if the current JVM should be shutdown. */ int restartRequested; /* WRAPPER_RESTART_REQUESTED_NO, WRAPPER_RESTART_REQUESTED_AUTOMATIC, or WRAPPER_RESTART_REQUESTED_CONFIGURED if the another JVM should be launched after the current JVM is shutdown. Only set if exitRequested is set. */ int stoppedPacketReceived; /* TRUE if the STOPPED packet was received before a restart. */ int restartPacketReceived; /* TRUE if the RESTART packet was received before a restart. */ int jvmRestarts; /* Number of times that a JVM has been launched since the wrapper was started. */ int restartDelay; /* Delay in seconds before restarting a new JVM. */ int restartReloadConf; /* TRUE if the configuration should be reloaded before a JVM restart. */ int isRestartDisabled; /* TRUE if restarts should be disabled. */ int isAutoRestartDisabled; /* TRUE if automatic restarts should be disabled. */ int requestThreadDumpOnFailedJVMExit; /* TRUE if the JVM should be asked to dump its state when it fails to halt on request. */ int requestThreadDumpOnFailedJVMExitDelay; /* Number of seconds to wait after the thread dump before killing the JVM. */ TICKS jvmLaunchTicks; /* The tick count at which the previous or current JVM was launched. */ int failedInvocationCount; /* The number of times that the JVM exited in less than successfulInvocationTime in a row. */ int successfulInvocationTime;/* Amount of time that a new JVM must be running so that the invocation will be considered to have been a success, leading to a reset of the restart count. */ int maxFailedInvocations; /* Maximum number of failed invocations in a row before the Wrapper will give up and exit. */ int outputFilterCount; /* Number of registered output filters. */ TCHAR **outputFilters; /* Array of output filters. */ int **outputFilterActionLists;/* Array of output filter action lists. */ TCHAR **outputFilterMessages; /* Array of output filter messages. */ int *outputFilterAllowWildFlags; /* Array of output filter flags that say whether or not wild cards in the filter can be processed. */ size_t *outputFilterMinLens; /* Array of the minimum text lengths that could possibly match the specified filter. Only used if it contains wildcards. */ TCHAR *pidFilename; /* Name of file to store wrapper pid in */ int pidFileStrict; /* TRUE if a preexisting pid file should cause an error. */ TCHAR *lockFilename; /* Name of file to store wrapper lock in */ TCHAR *javaPidFilename; /* Name of file to store jvm pid in */ TCHAR *javaIdFilename; /* Name of file to store jvm id in */ TCHAR *statusFilename; /* Name of file to store wrapper status in */ TCHAR *javaStatusFilename; /* Name of file to store jvm status in */ TCHAR *commandFilename; /* Name of a command file used to send commands to the Wrapper. */ int commandFileTests; /* True if test commands will be accepted via the command file. */ int commandPollInterval; /* Interval in seconds at which the existence of the command file is polled. */ TICKS commandTimeoutTicks; /* Tick count at which the command file will be checked next. */ TCHAR *anchorFilename; /* Name of an anchor file used to control when the Wrapper should quit. */ int anchorPollInterval; /* Interval in seconds at which the existence of the anchor file is polled. */ TICKS anchorTimeoutTicks; /* Tick count at which the anchor file will be checked next. */ int umask; /* Default umask for all files. */ int javaUmask; /* Default umask for the java process. */ int pidFileUmask; /* Umask to use when creating the pid file. */ int lockFileUmask; /* Umask to use when creating the lock file. */ int javaPidFileUmask; /* Umask to use when creating the java pid file. */ int javaIdFileUmask; /* Umask to use when creating the java id file. */ int statusFileUmask; /* Umask to use when creating the status file. */ int javaStatusFileUmask; /* Umask to use when creating the java status file. */ int anchorFileUmask; /* Umask to use when creating the anchor file. */ int ignoreSignals; /* Mask that determines where the Wrapper should ignore any catchable system signals. Can be ingored in the Wrapper and/or JVM. */ TCHAR *consoleTitle; /* Text to set the console title to. */ TCHAR *serviceName; /* Name of the service. */ TCHAR *serviceDisplayName; /* Display name of the service. */ TCHAR *serviceDescription; /* Description for service. */ TCHAR *hostName; /* The name of the current host. */ int pausable; /* Should the service be allowed to be paused? */ int pausableStopJVM; /* Should the JVM be stopped when the service is paused? */ int initiallyPaused; /* Should the Wrapper come up initially in a paused state? */ int logLFDelayThreshold; /* The LF Delay threshold to use when logging java output. */ #ifdef WIN32 int isSingleInvocation; /* TRUE if only a single invocation of an application should be allowed to launch. */ TCHAR *ntServiceLoadOrderGroup; /* Load order group name. */ TCHAR *ntServiceDependencies; /* List of Dependencies */ int ntServiceStartType; /* Mode in which the Service is installed. * {SERVICE_AUTO_START | SERVICE_DEMAND_START} */ DWORD ntServicePriorityClass; /* Priority at which the Wrapper and its JVMS will run. * {HIGH_PRIORITY_CLASS | IDLE_PRIORITY_CLASS | NORMAL_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS} */ TCHAR *ntServiceAccount; /* Account name to use when running as a service. NULL to use the LocalSystem account. */ TCHAR *ntServicePassword; /* Password to use when running as a service. NULL means no password. */ int ntServicePrompt; /* If true then the user will be prompted for a account name, domain, password when installing as a service. */ int ntServicePasswordPrompt; /* If true then the user will be prompted for a password when installing as a service. */ int ntServicePasswordPromptMask; /* If true then the password will be masked as it is input. */ int ntServiceInteractive; /* Should the service be allowed to interact with the desktop? */ int ntHideJVMConsole; /* Should the JVMs Console window be hidden when run as a service. True by default but GUIs will not be visible for JVMs prior to 1.4.0. */ int ntHideWrapperConsole; /* Should the Wrapper Console window be hidden when run as a service. */ HINSTANCE wrapperHInstance; /* The HINSTANCE of the Wrapper process. */ int wrapperConsoleHide; /* True if the Wrapper Console window should be hidden. */ HWND wrapperConsoleHWND; /* The HWND of the Wrapper's console if it was located. */ int wrapperConsoleVisible; /* True if the Wrapper Console window is visible. */ HWND jvmConsoleHandle; /* Pointer to the JVM Console handle if it exists. */ int jvmConsoleVisible; /* True if the JVM Console window is visible. */ int ntAllocConsole; /* True if a console should be allocated for the Service. */ int generateConsole; /* Make sure that a console is always generated to support thread dumps */ int threadDumpControlCode; /* Control code which can be used to trigger a thread dump. */ #else /* UNIX */ int daemonize; /* TRUE if the process should be spawned as a daemon process on launch. */ int signalHUPMode; /* Controls what happens when the Wrapper receives a HUP signal. */ int signalUSR1Mode; /* Controls what happens when the Wrapper receives a USR1 signal. */ int signalUSR2Mode; /* Controls what happens when the Wrapper receives a USR2 signal. */ int jvmStopped; /* Flag which remembers the the stopped state of the JVM process. */ #endif int pendingPingQueueOverflow; /* Flag which is set to true if the PendingPingQueue overflows the limit of WRAPPER_MAX_PENDING_PINGS. */ int pendingPingQueueOverflowEmptied; /* Flag which is set when the queue size is reduced to 0 after having overflowed. */ int pendingPingCount; /* Number of PendingPing events in the list. */ PPendingPing firstPendingPing; /* Pointer to the first PendingPing in the list. */ PPendingPing firstUnwarnedPendingPing; /* Pointer to the first PendingPing in the list for which a slow warning has not been logged. */ PPendingPing lastPendingPing; /* Pointer to the last PendingPing in the list. */ #ifdef WIN32 int ctrlEventCTRLCTrapped; /* CTRL_C_EVENT trapped. */ int ctrlEventCloseTrapped; /* CTRL_CLOSE_EVENT trapped. */ int ctrlEventLogoffTrapped; /* CTRL_LOGOFF_EVENT trapped. */ int ctrlEventShutdownTrapped;/* CTRL_SHUTDOWN_EVENT trapped. */ int *ctrlCodeQueue; /* Queue of control code ids trapped. */ int ctrlCodeQueueWriteIndex; int ctrlCodeQueueReadIndex; int ctrlCodeQueueWrapped; int ctrlCodePauseTrapped; /* SERVICE_CONTROL_PAUSE was trapped. */ int ctrlCodeContinueTrapped;/* SERVICE_CONTROL_CONTINUE was trapped. */ int ctrlCodeStopTrapped; /* SERVICE_CONTROL_STOP was trapped. */ int ctrlCodeShutdownTrapped;/* SERVICE_CONTROL_SHUTDOWN was trapped. */ int ctrlCodeDumpTrapped; /* The configured thread dump control code was trapped. */ #else int signalInterruptTrapped; /* SIGINT was trapped. */ int signalQuitTrapped; /* SIGQUIT was trapped. */ int signalChildTrapped; /* SIGCHLD was trapped. */ int signalTermTrapped; /* SIGTERM was trapped. */ int signalHUPTrapped; /* SIGHUP was trapped. */ int signalUSR1Trapped; /* SIGUSR1 was trapped. */ int signalUSR2Trapped; /* SIGUSR2 was trapped. */ #endif }; #define WRAPPER_SIGNAL_MODE_IGNORE (char)100 #define WRAPPER_SIGNAL_MODE_RESTART (char)101 #define WRAPPER_SIGNAL_MODE_SHUTDOWN (char)102 #define WRAPPER_SIGNAL_MODE_FORWARD (char)103 #define WRAPPER_MSG_START (char)100 #define WRAPPER_MSG_STOP (char)101 #define WRAPPER_MSG_RESTART (char)102 #define WRAPPER_MSG_PING (char)103 #define WRAPPER_MSG_STOP_PENDING (char)104 #define WRAPPER_MSG_START_PENDING (char)105 #define WRAPPER_MSG_STARTED (char)106 #define WRAPPER_MSG_STOPPED (char)107 #define WRAPPER_MSG_KEY (char)110 #define WRAPPER_MSG_BADKEY (char)111 #define WRAPPER_MSG_LOW_LOG_LEVEL (char)112 #define WRAPPER_MSG_PING_TIMEOUT (char)113 /* No longer used. But keep reserved to avoid future problems. */ #define WRAPPER_MSG_SERVICE_CONTROL_CODE (char)114 #define WRAPPER_MSG_PROPERTIES (char)115 /** Log commands are actually 116 + the LOG LEVEL (LEVEL_UNKNOWN ~ LEVEL_NONE), (116 ~ 124). */ #define WRAPPER_MSG_LOG (char)116 #define WRAPPER_MSG_LOGFILE (char)134 #define WRAPPER_MSG_APPEAR_ORPHAN (char)137 /* No longer used. But keep reserved to avoid future problems. */ #define WRAPPER_MSG_PAUSE (char)138 #define WRAPPER_MSG_RESUME (char)139 #define WRAPPER_MSG_GC (char)140 #define WRAPPER_PROCESS_DOWN 200 #define WRAPPER_PROCESS_UP 201 extern WrapperConfig *wrapperData; extern Properties *properties; extern TCHAR wrapperClasspathSeparator; /* Protocol Functions */ /** * Close the backend socket. */ extern void wrapperProtocolClose(); /** * Sends a command to the JVM process. * * @param function The command to send. (This is intentionally an 8-bit char.) * @param message Message to send along with the command. * * @return TRUE if there were any problems. */ extern int wrapperProtocolFunction(char function, const TCHAR *message); /** * Checks the status of the server backend. * * The backend will be initialized if the JVM is in a state where it should * be up, otherwise the backend will be left alone. * * If the forceOpen flag is set then an attempt will be made to initialize * the backend regardless of the JVM state. * * Returns TRUE if the backend is open and ready on return, FALSE if not. */ extern int wrapperCheckServerBackend(int forceOpen); /** * Read any data sent from the JVM. This function will loop and read as many * packets are available. The loop will only be allowed to go for 250ms to * ensure that other functions are handled correctly. * * Returns 0 if all available data has been read, 1 if more data is waiting. */ extern int wrapperProtocolRead(); /****************************************************************************** * Utility Functions *****************************************************************************/ /** * Does any necessary post processing on the command string. * This function assumes that command has been malloced. It will either return * the string as is, or return a modified string. When a modified string is * returned the orignal command buffer will always be freed. * * 1) Replace the first instance of the %WRAPPER_COMMAND_FILLER_N% environment * variable so that the total command length will be equal to or greater than * the length specified by N. The padding will be the length plus a series of * Xs terminated by a single Y. This is mainly for testing. * * @param command The original command. * * @return The modifed command. */ extern TCHAR *wrapperPostProcessCommandElement(TCHAR *command); /** * Test function to pause the current thread for the specified amount of time. * This is used to test how the rest of the Wrapper behaves when a particular * thread blocks for any reason. * * @param pauseTime Number of seconds to pause for. -1 will pause indefinitely. * @param threadName Name of the thread that will be logged prior to pausing. */ extern void wrapperPauseThread(int pauseTime, const TCHAR *threadName); /** * Function that will recursively attempt to match two strings where the * pattern can contain '?' or '*' wildcard characters. * * @param text Text to be searched. * @param pattern Pattern to search for. * @param patternLen Length of the pattern. * @param minTextLen Minimum number of characters that the text needs to possibly match the pattern. * * @return TRUE if found, FALSE otherwise. */ extern int wrapperWildcardMatch(const TCHAR *text, const TCHAR *pattern, size_t minTextLen); /** * Calculates the minimum text length which could be matched by the specified pattern. * Patterns can contain '*' or '?' wildcards. * '*' matches 0 or more characters. * '?' matches exactly one character. * * @param pattern Pattern to calculate. * * @return The minimum text length of the pattern. */ extern size_t wrapperGetMinimumTextLengthForPattern(const TCHAR *pattern); /** * Returns a constant text representation of the specified Wrapper State. * * @param wState The Wrapper State whose name is being requested. * * @return Thre requested Wrapper State. */ extern const TCHAR *wrapperGetWState(int wState); /** * Returns a constant text representation of the specified Java State. * * @param jState The Java State whose name is being requested. * * @return Thre requested Java State. */ extern const TCHAR *wrapperGetJState(int jState); extern struct tm wrapperGetReleaseTime(); extern struct tm wrapperGetBuildTime(); #ifdef WIN32 extern int initializeStartup(); extern void disposeStartup(); #endif extern void disposeJavaIO(); extern void disposeTimer(); extern int showHostIds(int logLevel); extern void wrapperLoadHostName(); /** * Parses a list of actions for an action property. * * @param actionNameList A space separated list of action names. * @param propertyName The name of the property where the action name originated. * * @return an array of integer action ids, or NULL if there were any problems. */ extern int *wrapperGetActionListForNames(const TCHAR *actionNameList, const TCHAR *propertyName); /** * Performs the specified action, * * @param actionList An array of action Ids ending with a value ACTION_LIST_END. * Negative values are standard actions, positive are user * custom events. * @param triggerMsg The reason the actions are being fired. * @param actionSourceCode Tracks where the action originated. * @param logForActionNone Flag stating whether or not a message should be logged * for the NONE action. * @param exitCode Error code to use in case the action results in a shutdown. */ extern void wrapperProcessActionList(int *actionList, const TCHAR *triggerMsg, int actionSourceCode, int logForActionNone, int exitCode); extern void wrapperAddDefaultProperties(); extern int wrapperLoadConfigurationProperties(int preload); extern void wrapperGetCurrentTime(struct timeb *timeBuffer); #ifdef WIN32 extern void wrapperInitializeProfileCounters(); extern void wrapperDumpPageFaultUsage(); extern void updateStringValue(TCHAR **ptr, const TCHAR *value); extern TCHAR** wrapperGetSystemPath(); extern int wrapperGetJavaHomeFromWindowsRegistry(TCHAR *javaHome); #endif extern int wrapperCheckRestartTimeOK(); extern int wrapperBuildJavaClasspath(TCHAR **classpath); /** * command is a pointer to a pointer of an array of character strings. * length is the number of strings in the above array. */ extern int wrapperBuildJavaCommandArray(TCHAR ***strings, int *length, int addQuotes, const TCHAR *classpath); extern void wrapperFreeJavaCommandArray(TCHAR **strings, int length); extern int wrapperInitialize(); extern void wrapperDispose(); /** * Returns the file name base as a newly malloced TCHAR *. The resulting * base file name will have any path and extension stripped. * * baseName should be long enough to always contain the base name. * (strlen(fileName) + 1) is safe. */ extern void wrapperGetFileBase(const TCHAR *fileName, TCHAR *baseName); /** * Output the version. */ extern void wrapperVersionBanner(); /** * Output the application usage. */ extern void wrapperUsage(TCHAR *appName); /** * Parse the main arguments. * * Returns FALSE if the application should exit with an error. A message will * already have been logged. */ extern int wrapperParseArguments(int argc, TCHAR **argv); /** * Called when the Wrapper detects that the JVM process has exited. * Contains code common to all platforms. */ extern void wrapperJVMProcessExited(TICKS nowTicks, int exitCode); /** * Read and process any output from the child JVM Process. * * When maxTimeMS is non-zero this function will only be allowed to run for that maximum * amount of time. This is done to make sure the calling function is allowed CPU for * other activities. When timing out for this reason when there is more data in the * pipe, this function will return TRUE to let the calling code know that it should * not to any unnecessary sleeps. Otherwise FALSE will be returned. * * @param maxTimeMS The maximum number of milliseconds that this function will be allowed * to run without returning. In reality no new reads will happen after * this time, but actual processing may take longer. * * @return TRUE if the calling code should call this function again as soon as possible. */ extern int wrapperReadChildOutput(int maxTimeMS); /** * Changes the current Wrapper state. * * wState - The new Wrapper state. */ extern void wrapperSetWrapperState(int wState); /** * Updates the current state time out. * * nowTicks - The current tick count at the time of the call, may be -1 if * delay is negative. * delay - The delay in seconds, added to the nowTicks after which the state * will time out, if negative will never time out. */ extern void wrapperUpdateJavaStateTimeout(TICKS nowTicks, int delay); /** * Changes the current Java state. * * jState - The new Java state. * nowTicks - The current tick count at the time of the call, may be -1 if * delay is negative. * delay - The delay in seconds, added to the nowTicks after which the state * will time out, if negative will never time out. */ extern void wrapperSetJavaState(int jState, TICKS nowTicks, int delay); /****************************************************************************** * Platform specific methods *****************************************************************************/ #ifdef WIN32 extern void wrapperCheckConsoleWindows(); /** * checks the digital Signature of the binary and reports the result. */ extern BOOL verifyEmbeddedSignature(); extern int exceptionFilterFunction(PEXCEPTION_POINTERS exceptionPointers); BOOL extern elevateThis(int argc, TCHAR **argv); BOOL extern duplicateSTD(); BOOL extern myShellExec(HWND hwnd, LPCTSTR pszVerb, LPCTSTR pszPath, LPCTSTR pszParameters, LPCTSTR pszDirectory, TCHAR* namedPipeName); BOOL extern runElevated( __in LPCTSTR pszPath, __in_opt LPCTSTR pszParameters, __in_opt LPCTSTR pszDirectory, TCHAR* namedPipeName); BOOL extern isElevated(); BOOL extern isVista(); extern void wrapperMaintainControlCodes(); #else extern void wrapperMaintainSignals(); extern TCHAR* findPathOf(const TCHAR *exe, const TCHAR* name); #endif /** * Execute initialization code to get the wrapper set up. */ extern int wrapperInitializeRun(); /** * Cause the current thread to sleep for the specified number of milliseconds. * Sleeps over one second are not allowed. * * @param ms Number of milliseconds to wait for. * * @return TRUE if the was interrupted, FALSE otherwise. Neither is an error. */ extern int wrapperSleep(int ms); /** * Reports the status of the wrapper to the service manager * Possible status values: * WRAPPER_WSTATE_STARTING * WRAPPER_WSTATE_STARTED * WRAPPER_WSTATE_STOPPING * WRAPPER_WSTATE_STOPPED */ extern void wrapperReportStatus(int useLoggerQueue, int status, int errorCode, int waitHint); /** * Reads a single block of data from the child pipe. * * @param blockBuffer Pointer to the buffer where the block will be read. * @param blockSize Maximum number of bytes to read. * @param readCount Pointer to an int which will hold the number of bytes * actually read by the call. * * Returns TRUE if there were any problems, FALSE otherwise. */ extern int wrapperReadChildOutputBlock(char *blockBuffer, int blockSize, int *readCount); /** * Checks on the status of the JVM Process. * Returns WRAPPER_PROCESS_UP or WRAPPER_PROCESS_DOWN */ extern int wrapperGetProcessStatus(TICKS nowTicks, int sigChild); /** * Pauses before launching a new JVM if necessary. */ extern void wrapperPauseBeforeExecute(); /** * Launches a JVM process and store it internally * * @return TRUE if there were any problems. When this happens the Wrapper will not try to restart. */ extern int wrapperExecute(); /** * Returns a tick count that can be used in combination with the * wrapperGetTickAgeSeconds() function to perform time keeping. */ extern TICKS wrapperGetTicks(); /** * Runs some assertion checks on the tick timer logic. */ extern int wrapperTickAssertions(); /** * Outputs a a log entry describing what the memory dump columns are. */ extern void wrapperDumpMemoryBanner(); /** * Outputs a log entry at regular intervals to track the memory usage of the * Wrapper and its JVM. */ extern void wrapperDumpMemory(); /** * Outputs a log entry at regular intervals to track the CPU usage over each * interval for the Wrapper and its JVM. */ extern void wrapperDumpCPUUsage(); /****************************************************************************** * Wrapper inner methods. *****************************************************************************/ /** * Immediately kill the JVM process and set the JVM state to * WRAPPER_JSTATE_DOWN. */ extern int wrapperKillProcessNow(); /** * Puts the Wrapper into a state where the JVM will be killed at the soonest * possible opportunity. It is necessary to wait a moment if a final thread * dump is to be requested. This call wll always set the JVM state to * WRAPPER_JSTATE_KILLING. */ extern void wrapperKillProcess(); /** * Launch the wrapper as a console application. */ extern int wrapperRunConsole(); /** * Launch the wrapper as a service application. */ extern int wrapperRunService(); /** * Used to ask the state engine to pause the JVM and Wrapper * * @param actionSourceCode Tracks where the action originated. */ extern void wrapperPauseProcess(int actionSourceCode); /** * Used to ask the state engine to resume the JVM and Wrapper * * @param actionSourceCode Tracks where the action originated. */ extern void wrapperResumeProcess(int actionSourceCode); /** * Detaches the Java process so the Wrapper will if effect forget about it. */ extern void wrapperDetachJava(); /** * Used to ask the state engine to shut down the JVM and Wrapper. * * @param exitCode Exit code to use when shutting down. * @param force True to force the Wrapper to shutdown even if some configuration * had previously asked that the JVM be restarted. This will reset * any existing restart requests, but it will still be possible for * later actions to request a restart. */ extern void wrapperStopProcess(int exitCode, int force); /** * Depending on the current state, we want to change the exact message displayed when restarting the JVM. * * The logic here needs to match that in wrapperRestartProcess. */ extern const TCHAR *wrapperGetRestartProcessMessage(); /** * Used to ask the state engine to shut down the JVM. */ extern void wrapperRestartProcess(); /** * Sends a command off to the JVM asking it to perform a garbage collection sweep. * * @param actionSourceCode Tracks where the action originated. */ extern void wrapperRequestJVMGC(int actionSourceCode); /** * Loops over and strips all double quotes from prop and places the * stripped version into propStripped. * * The exception is double quotes that are preceeded by a backslash * in this case the backslash is stripped. * * If two backslashes are found in a row, then the first escapes the * second and the second is removed. */ extern void wrapperStripQuotes(const TCHAR *prop, TCHAR *propStripped); /** * Adds quotes around the specified string in such a way that everything is * escaped correctly. If the bufferSize is not large enough then the * required size will be returned. 0 is returned if successful. */ extern size_t wrapperQuoteValue(const TCHAR* value, TCHAR *buffer, size_t bufferSize); /** * Checks the quotes in the value and displays an error if there are any problems. * This can be useful to help users debug quote problems. */ extern int wrapperCheckQuotes(const TCHAR *value, const TCHAR *propName); /** * The main event loop for the wrapper. Handles all state changes and events. */ extern void wrapperEventLoop(); extern void wrapperBuildKey(); /** * Send a signal to the JVM process asking it to dump its JVM state. */ extern void wrapperRequestDumpJVMState(); /** * Build the java command line. * * @return TRUE if there were any problems. */ extern int wrapperBuildJavaCommand(); /** * Requests a lock on the tick mutex. */ extern int wrapperLockTickMutex(); /** * Releases a lock on the tick mutex. */ extern int wrapperReleaseTickMutex(); /** * Calculates a tick count using the system time. */ extern TICKS wrapperGetSystemTicks(); /** * Returns difference in seconds between the start and end ticks. This function * handles cases where the tick counter has wrapped between when the start * and end tick counts were taken. See the wrapperGetTicks() function. */ extern int wrapperGetTickAgeSeconds(TICKS start, TICKS end); /** * Returns difference in ticks between the start and end ticks. This function * handles cases where the tick counter has wrapped between when the start * and end tick counts were taken. See the wrapperGetTicks() function. * * This can be done safely in 32 bits */ extern int wrapperGetTickAgeTicks(TICKS start, TICKS end); /** * Returns TRUE if the specified tick timeout has expired relative to the * specified tick count. */ extern int wrapperTickExpired(TICKS nowTicks, TICKS timeoutTicks); /** * Returns a tick count that is the specified number of seconds later than * the base tick count. */ extern TICKS wrapperAddToTicks(TICKS start, int seconds); /** * Sets the working directory of the Wrapper to the specified directory. * The directory can be relative or absolute. * If there are any problems then a non-zero value will be returned. * * @param dir Directory to change to. * @param logErrors TRUE if errors should be logged. */ extern int wrapperSetWorkingDir(const TCHAR* dir, int logErrors); /****************************************************************************** * Protocol callback functions *****************************************************************************/ extern void wrapperLogSignaled(int logLevel, TCHAR *msg); extern void wrapperKeyRegistered(TCHAR *key); /** * Called when a ping is first determined to be slower than the wrapper.ping.alert.threshold. * This will happen before it has actually been responded to. */ extern void wrapperPingSlow(); /** * Called when a ping is responded to, but was slower than the wrapper.ping.alert.threshold. * * @param tickAge The number of seconds it took to respond. */ extern void wrapperPingRespondedSlow(int tickAge); /** * Called when a ping response is received. * * @param pingSendTicks Time in ticks when the ping was originally sent. * @param queueWarnings TRUE if warnings about the queue should be logged, FALSE if the ping response did not contain a time. */ extern void wrapperPingResponded(TICKS pingSendTicks, int queueWarnings); extern void wrapperPingTimeoutResponded(); extern void wrapperStopRequested(int exitCode); extern void wrapperRestartRequested(); extern void wrapperStopPendingSignaled(int waitHint); extern void wrapperStoppedSignaled(); extern void wrapperStartPendingSignaled(int waitHint); extern void wrapperStartedSignaled(); /****************************************************************************** * Inner types and methods for loading Wrapper configuration. *****************************************************************************/ /* Callback parameter for loading the file specified by wrapper.java.additional_file configuration property. */ typedef struct LoadParameterFileCallbackParam LoadParameterFileCallbackParam; struct LoadParameterFileCallbackParam { int stripQuote; /* Value of wrapper.java.additional_file.stripquotes property */ TCHAR **strings; /* Array of character strings to which configurations are loaded */ int index; /* Index of a string in `strings' to which a configuration are copied next */ int isJVMParam; /* Indicates whether the loaded parameters will be JVM parameters */ }; #ifdef CUNIT extern void tsJAP_testJavaAdditionalParamSuite(void); #endif /* CUNIT */ #endif wrapper_3.5.26_src/src/c/wrapper.ico100644 0 0 61176 12440202300 14552 0ustar 0 0  (h h&  v  00h'00..00 %<( %&)(:?JFDN[zokl|}Bb2~K@\_-v\P掸?}8n:ʸț_kpU0D(  "),4-*@40"7;9C999(:=->@EFE KW P]Q\T`aSN\l\[Ydddofbzhabkjqiersqssavywvuxpyr\{-}{yt}};]}l|M}]jf\ťJ1CƬ 7!ͳ!1:ε,͸"Ѻr""ؾǻ O_SLJK>D+ GM\!0:?#8]U&7E9/5-CZF$TN;*652c( YW6 1ARñʶ̷))!"'"!,7TYrĹǾǻȽȼȻȺȻȹȹȹɻɸɷɷ̾ͿWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW22222WWWWWWWWWWWWWWWWWWWWWWWWWW22222222WWWWWWWJJJJJWWWWWWWWWWWWW22WWWW225WWWJJJJJJJVWWWWWWWWWWWW5"   )WWWWWWWWWW  WWWP@4WWWWW WWWWWW W'BWWWWJLWW22WWWVUWW WWW WWW;-WOJWWWWW2.WRJWWWW WW WWWWW7DMWWWWWWW8=HWWWWWW WW WWWWQA3WWWWWWKE<.WWWWW WWW WWUSW/2WWWWJKWW.:WWW WWWWWW (CWW90WIJWWWW,&  WWWWWWWWWWT*6G% +!WWWWWWWWWWWWW#UJJJJJNW1$WWWWWW?>WWWWWWWWWWWWWWJJFJWWWWW222WWWWW22WWWWWWWWWWWWWWWWWWWWWWW222WWWW22WWWWWWWWWWWWWWWWWWWWWWWWW22222222WWWWWWWWWWWWWWWWWWWWWWWWWW22222WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW??|yÇ'Ꮟ'2x~???( @ "_"""""""""""""""ȻȻȻȻȻȻȻRy"""T"v""!ɼKȻȻȻȻȻȻȻ[!N~Ր㍎􍎍s򒒐찥ʶdЍ|􊏏ɻr",byѬЍdJ퍎񂓕k>idʽdȻȻ#b""7Ϳ翮t򍎍퍎J%ȹȻȻF"5"N,ɷȻͿK,ȹȻ%7YȽKͿ>ɸ'ȺǾTR󍎍򄈈p:ͿɷYC"Ȼ*ȻȺǾTD |򍎍󍎍Rb׌ñĹ\:zKȼȻȻz z)A׍b̷̾񋌌q)Q퉐<ͿȻȻȻȻȻȹ3k!I뎍XmȻ*ȻȻȻȻȻ7 !"""a"""""""v"T"""y""""""""""""""""_??|yÇ'Ꮟ'2x~???(0`q[LBϺ2 ˿~ȸ$D3w?"wkoY ~i_w~?c㏎??q>d~(0`xrl_XSQJIFCŲƳ61˶˷к";<GOZp÷ǾǾȽȻ666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666!!!!!!66666666666666666666666666666666666666666!!!!!!!!!666666666666666666666666666666666666666!!!!!!!!!!!66666666666555555556666666666666666666!!!66666!!!!666666655555555556666666666666666666!!!66666666655556666666666666666666! 66666666666666666666666/#%*66666666666666666666666666556!!!66666665)6666666666!!!66666555666!!!666665556666666666666!!6666556666666!!6665556666666666666666!!6555666666666!!6556666666666666666666!05566666666666!$16666666666666666666624&6666666666663'!666666666666666666655-!!6666666665556!!666666666666666655566!!6666666556666!!6666666666666556666!!6666555666666!!666666666666655 66!!6555666666 !66666666666666666.55+4( !666666666666666666666555566 ,55"!666666!!6666666666666666666665555555556666!!6666666666!!!6666666666666666666665555566666666!!!666666666!!!66666666666666666666666666666666666!!!6666666!!!666666666666666666666666666666666666!!!!66666!!!66666666666666666666666666666666666666!!!!!!!!!!!666666666666666666666666666666666666666!!!!!!!!!66666666666666666666666666666666666666666!!!!!!666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666?c㏎??q>d~(0` """"""""<""""""""""WȻȻpȻpȻ<""""""""""""<ȻȻȻȻȻȻȻȻ"p"""""W"""""Ȼ<ȻȻȻȻȻȻȻȻȻȻ"""d~wrapper_3.5.26_src/src/c/wrapper_file.c100644 0 0 62351 12440202301 15216 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * Author: * Tanuki Software Development Team */ #include #include #include #ifdef WIN32 #include #include #include #include #else #include #include #include #include #include #if defined(IRIX) #define PATH_MAX FILENAME_MAX #endif #endif #include "wrapper_file.h" #include "logger.h" #include "wrapper_i18n.h" #include "property.h" #ifndef TRUE #define TRUE -1 #endif #ifndef FALSE #define FALSE 0 #endif #define MAX_INCLUDE_DEPTH 10 /* Structure used by configFileReader to read files. */ typedef struct ConfigFileReader ConfigFileReader; struct ConfigFileReader { ConfigFileReader_Callback callback; void *callbackParam; int enableIncludes; int preload; /* debugIncludes controls whether or not debug output is logged. It is set using directives in the file being read. */ int debugIncludes; /* debugProperties controls whether or not debug output is logged. It is set using directives in the file being read. */ int debugProperties; }; /** * Tests whether a file exists. * * @return TRUE if exists, FALSE otherwise. */ int wrapperFileExists(const TCHAR * filename) { FILE * file; if ((file = _tfopen(filename, TEXT("r")))) { fclose(file); return TRUE; } return FALSE; } #ifdef WIN32 /** * @param path to check. * @param advice 0 if advice should be displayed. * * @return advice or advice + 1 if advice was logged. */ int wrapperGetUNCFilePath(const TCHAR *path, int advice) { TCHAR drive[4]; DWORD result; /* See if the path starts with a drive. Some users use forward slashes in the paths. */ if ((path != NULL) && (_tcslen(path) >= 3) && (path[1] == TEXT(':')) && ((path[2] == TEXT('\\')) || (path[2] == TEXT('/')))) { _tcsncpy(drive, path, 2); drive[2] = TEXT('\\'); drive[3] = TEXT('\0'); result = GetDriveType(drive); if (result == DRIVE_REMOTE) { if (advice == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("The following path in your Wrapper configuration file is to a mapped Network\n Drive. Using mapped network drives is not recommeded as they will fail to\n be resolved correctly under certain circumstances. Please consider using\n UNC paths (\\\\\\\\path). Additional refrences will be ignored.\n Path: %s"), path); advice++; } } else if (result == DRIVE_NO_ROOT_DIR) { if (advice == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("The following path in your Wrapper configuration file could not be resolved.\n Please make sure the path exists. If the path is a network share, it may be\n that the current user is unable to resolve it. Please consider using UNC\n paths (\\\\\\\\path) or run the service as another user\n (see wrapper.ntservice.account). Additional refrences will be ignored.\n Path: %s"), path); advice++; } } } return advice; } #endif /** * Read configuration file. */ int configFileReader_Read(ConfigFileReader *reader, const TCHAR *filename, int fileRequired, int depth, const TCHAR *parentFilename, int parentLineNumber, const TCHAR *argCommand, const TCHAR *originalWorkingDir, PHashMap warnedVarMap, int logWarnings, int logWarningLogLevel, int isDebugging) { FILE *stream; char bufferMB[MAX_PROPERTY_NAME_VALUE_LENGTH]; TCHAR expBuffer[MAX_PROPERTY_NAME_VALUE_LENGTH]; TCHAR *trimmedBuffer; size_t trimmedBufferLen; TCHAR *c; TCHAR *d; size_t i, j; size_t len; int quoted; TCHAR *absoluteBuffer; int hadBOM; int lineNumber; char *encodingMB; #ifdef WIN32 int encoding; #else char* encoding; char* interumEncoding; #endif int includeRequired; int readResult = CONFIG_FILE_READER_SUCCESS; int ret; TCHAR *bufferW; #ifdef WIN32 int size; #endif #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("configFileReader_Read('%s', required %d, depth %d, parent '%s', number %d, debugIncludes %d, preload %d)"), filename, fileRequired, depth, (parentFilename ? parentFilename : TEXT("")), parentLineNumber, reader->debugIncludes, reader->preload ); #endif /* Look for the specified file. */ if ((stream = _tfopen(filename, TEXT("rb"))) == NULL) { /* Unable to open the file. */ if (reader->debugIncludes || fileRequired) { if (depth > 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%sIncluded configuration file not found: %s\n Referenced from: %s (line %d)\n Current working directory: %s"), (reader->debugIncludes ? TEXT(" ") : TEXT("")), filename, parentFilename, parentLineNumber, originalWorkingDir); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Configuration file not found: %s\n Current working directory: %s"), filename, originalWorkingDir); } } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Configuration file not found: %s"), filename); #endif } return CONFIG_FILE_READER_FAIL; } if (reader->debugIncludes) { if (!reader->preload) { if (depth > 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Reading included configuration file, %s"), filename); } else { /* Will not actually get here because the debug includes can't be set until it is loaded. log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Reading configuration file, %s"), filename); */ } } } /* Load in the first row of configurations to check the encoding. */ if (fgets(bufferMB, MAX_PROPERTY_NAME_VALUE_LENGTH, stream)) { /* If the file starts with a BOM (Byte Order Marker) then we want to skip over it. */ if ((bufferMB[0] == (char)0xef) && (bufferMB[1] == (char)0xbb) && (bufferMB[2] == (char)0xbf)) { i = 3; hadBOM = TRUE; } else { i = 0; hadBOM = FALSE; } /* Does the file start with "#encoding="? */ if ((bufferMB[i++] == '#') && (bufferMB[i++] == 'e') && (bufferMB[i++] == 'n') && (bufferMB[i++] == 'c') && (bufferMB[i++] == 'o') && (bufferMB[i++] == 'd') && (bufferMB[i++] == 'i') && (bufferMB[i++] == 'n') && (bufferMB[i++] == 'g') && (bufferMB[i++] == '=')) { encodingMB = bufferMB + i; i = 0; while ((encodingMB[i] != ' ') && (encodingMB[i] != '\n') && (encodingMB[i] != '\r')) { i++; } encodingMB[i] = '\0'; if ((hadBOM) && (strIgnoreCaseCmp(encodingMB, "UTF-8") != 0)) { } if (getEncodingByName(encodingMB, &encoding) == TRUE) { fclose(stream); return CONFIG_FILE_READER_FAIL; } } else { #ifdef WIN32 encoding = GetACP(); #else encoding = nl_langinfo(CODESET); #ifdef MACOSX if (strlen(encoding) == 0) { encoding = "UTF-8"; } #endif #endif } } else { /* Failed to read the first line of the file. */ #ifdef WIN32 encoding = GetACP(); #else encoding = nl_langinfo(CODESET); #ifdef MACOSX if (strlen(encoding) == 0) { encoding = "UTF-8"; } #endif #endif } fclose(stream); if ((stream = _tfopen(filename, TEXT("rb"))) == NULL) { /* Unable to open the file. */ if (reader->debugIncludes || fileRequired) { if (depth > 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%sIncluded configuration file, %s, was not found."), (reader->debugIncludes ? TEXT(" ") : TEXT("")), filename); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Configuration file, %s, was not found."), filename); } } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Configuration file not found: %s"), filename); #endif } return CONFIG_FILE_READER_FAIL; } /* Read all of the configurations */ lineNumber = 1; do { c = (TCHAR*)fgets(bufferMB, MAX_PROPERTY_NAME_VALUE_LENGTH, stream); if (c != NULL) { #ifdef WIN32 ret = multiByteToWideChar(bufferMB, encoding, &bufferW, TRUE); #else interumEncoding = nl_langinfo(CODESET); #ifdef MACOSX if (strlen(interumEncoding) == 0) { interumEncoding = "UTF-8"; } #endif ret = multiByteToWideChar(bufferMB, encoding, interumEncoding, &bufferW, TRUE); #endif if (ret) { if (bufferW) { /* bufferW contains an error message. */ if (!reader->preload) { if (depth > 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%sIncluded configuration file, %s, contains a problem on line #%d and could not be read. (%s)"), (reader->debugIncludes ? TEXT(" ") : TEXT("")), filename, lineNumber, bufferW); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Configuration file, %s, contains a problem on line #%d and could not be read. (%s)"), filename, lineNumber, bufferW); } } free(bufferW); } else { outOfMemory(TEXT("RCF"), 1); } fclose(stream); return CONFIG_FILE_READER_FAIL; } #ifdef _DEBUG /* The line feeds are not yet stripped here. */ /* #ifdef WIN32 wprintf(TEXT("%s:%d (%d): [%s]\n"), filename, lineNumber, encoding, bufferW); #else wprintf(TEXT("%S:%d (%s to %s): [%S]\n"), filename, lineNumber, encoding, interumEncoding, bufferW); #endif */ #endif c = bufferW; /* Always strip both ^M and ^J off the end of the line, this is done rather * than simply checking for \n so that files will work on all platforms * even if their line feeds are incorrect. */ if ((d = _tcschr(bufferW, 0x0d /* ^M */)) != NULL) { d[0] = TEXT('\0'); } if ((d = _tcschr(bufferW, 0x0a /* ^J */)) != NULL) { d[0] = TEXT('\0'); } /* Strip any whitespace from the front of the line. */ trimmedBuffer = bufferW; while ((trimmedBuffer[0] == TEXT(' ')) || (trimmedBuffer[0] == 0x08)) { trimmedBuffer++; } /* If the line does not start with a comment, make sure that * any comment at the end of line are stripped. If any any point, a * double hash, '##', is encountered it should be interpreted as a * hash in the actual property rather than the beginning of a comment. */ if (trimmedBuffer[0] != TEXT('#')) { len = _tcslen(trimmedBuffer); i = 0; quoted = 0; while (i < len) { if (trimmedBuffer[i] == TEXT('"')) { quoted = !quoted; } else if ((trimmedBuffer[i] == TEXT('#')) && (!quoted)) { /* Checking the next character will always be ok because it will be * '\0 at the end of the string. */ if (trimmedBuffer[i + 1] == TEXT('#')) { /* We found an escaped #. Shift the rest of the string * down by one character to remove the second '#'. * Include the shifting of the '\0'. */ for (j = i + 1; j <= len; j++) { trimmedBuffer[j - 1] = trimmedBuffer[j]; } len--; } else { /* We found a comment. So this is the end. */ trimmedBuffer[i] = TEXT('\0'); len = i; } } i++; } } /* Strip any whitespace from the end of the line. */ trimmedBufferLen = _tcslen(trimmedBuffer); while ((trimmedBufferLen > 0) && ((trimmedBuffer[trimmedBufferLen - 1] == TEXT(' ')) || (trimmedBuffer[trimmedBufferLen - 1] == 0x08))) { trimmedBuffer[--trimmedBufferLen] = TEXT('\0'); } /* Only look at lines which contain data and do not start with a '#' * If the line starts with '#include' then recurse to the include file */ if (_tcslen(trimmedBuffer) > 0) { if (reader->enableIncludes && strcmpIgnoreCase(trimmedBuffer, TEXT("#include.debug")) == 0) { /* Enable include file debugging. */ if (reader->preload == FALSE) { reader->debugIncludes = TRUE; if (depth == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Base configuration file is %s"), filename); } } else { reader->debugIncludes = FALSE; } } else if (reader->enableIncludes && ((_tcsstr(trimmedBuffer, TEXT("#include ")) == trimmedBuffer) || (_tcsstr(trimmedBuffer, TEXT("#include.required ")) == trimmedBuffer))) { if (_tcsstr(trimmedBuffer, TEXT("#include.required ")) == trimmedBuffer) { /* The include file is required. */ includeRequired = TRUE; c = trimmedBuffer + 18; } else { /* Include file, if the file does not exist, then ignore it */ includeRequired = FALSE; c = trimmedBuffer + 9; } /* Strip any leading whitespace */ while ((c[0] != TEXT('\0')) && (c[0] == TEXT(' '))) { c++; } /* The filename may contain environment variables, so expand them. */ if (reader->debugIncludes) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Found #include file in %s: %s"), filename, c); } evaluateEnvironmentVariables(c, expBuffer, MAX_PROPERTY_NAME_VALUE_LENGTH, logWarnings, warnedVarMap, logWarningLogLevel); if (reader->debugIncludes && (_tcscmp(c, expBuffer) != 0)) { /* Only show this log if there were any environment variables. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" After environment variable replacements: %s"), expBuffer); } /* Now obtain the real absolute path to the include file. */ #ifdef WIN32 /* Find out how big the absolute path will be */ size = GetFullPathName(expBuffer, 0, NULL, NULL); /* Size includes '\0' */ if (!size) { if (reader->debugIncludes || includeRequired) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Unable to resolve the full path of included configuration file: %s (%s)\n Referenced from: %s (line %d)\n Current working directory: %s"), expBuffer, getLastErrorText(), filename, lineNumber, originalWorkingDir); } absoluteBuffer = NULL; } else { absoluteBuffer = malloc(sizeof(TCHAR) * size); if (!absoluteBuffer) { outOfMemory(TEXT("RCF"), 1); } else { if (!GetFullPathName(expBuffer, size, absoluteBuffer, NULL)) { if (reader->debugIncludes || includeRequired) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Unable to resolve the full path of included configuration file: %s (%s)\n Referenced from: %s (line %d)\n Current working directory: %s"), expBuffer, getLastErrorText(), filename, lineNumber, originalWorkingDir); } free(absoluteBuffer); absoluteBuffer = NULL; } } } #else absoluteBuffer = malloc(sizeof(TCHAR) * (PATH_MAX + 1)); if (!absoluteBuffer) { outOfMemory(TEXT("RCF"), 2); } else { if (_trealpathN(expBuffer, absoluteBuffer, PATH_MAX + 1) == NULL) { if (reader->debugIncludes || includeRequired) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Unable to resolve the full path of included configuration file: %s (%s)\n Referenced from: %s (line %d)\n Current working directory: %s"), expBuffer, getLastErrorText(), filename, lineNumber, originalWorkingDir); } free(absoluteBuffer); absoluteBuffer = NULL; } } #endif if (absoluteBuffer) { if (depth < MAX_INCLUDE_DEPTH) { readResult = configFileReader_Read(reader, absoluteBuffer, includeRequired, depth + 1, filename, lineNumber, argCommand, originalWorkingDir, warnedVarMap, logWarnings, logWarningLogLevel, isDebugging); if (readResult == CONFIG_FILE_READER_SUCCESS) { /* Ok continue. */ } else if ((readResult == CONFIG_FILE_READER_FAIL) || (readResult == CONFIG_FILE_READER_HARD_FAIL)) { /* Failed. */ if (includeRequired) { /* Include file was required, but we failed to read it. */ if (!reader->preload) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%sThe required configuration file, %s, was not loaded.\n%s Referenced from: %s (line %d)"), (reader->debugIncludes ? TEXT(" ") : TEXT("")), absoluteBuffer, (reader->debugIncludes ? TEXT(" ") : TEXT("")), filename, lineNumber); } readResult = CONFIG_FILE_READER_HARD_FAIL; } if (readResult == CONFIG_FILE_READER_HARD_FAIL) { /* Can't continue. */ break; } else { /* Failed but continue. */ readResult = CONFIG_FILE_READER_SUCCESS; } } else { _tprintf(TEXT("Unexpected load error %d\n"), readResult); /* continue. */ readResult = CONFIG_FILE_READER_SUCCESS; } } else { if (reader->debugIncludes) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Unable to include configuration file, %s, because the max include depth was reached."), absoluteBuffer); } } free(absoluteBuffer); } else { if (includeRequired) { /* Include file was required, but we failed to read it. */ if (!reader->preload) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%sThe required configuration file, %s, was not read.\n%s Referenced from: %s (line %d)"), (reader->debugIncludes ? TEXT(" ") : TEXT("")), expBuffer, (reader->debugIncludes ? TEXT(" ") : TEXT("")), filename, lineNumber); } readResult = CONFIG_FILE_READER_HARD_FAIL; break; } } } else if (strcmpIgnoreCase(trimmedBuffer, TEXT("#properties.debug")) == 0) { if (!reader->preload) { /* Enable property debugging. */ reader->debugProperties = TRUE; } } else if (trimmedBuffer[0] != TEXT('#')) { /*_tprintf(TEXT("%s\n"), trimmedBuffer);*/ if (!(*reader->callback)(reader->callbackParam, filename, lineNumber, trimmedBuffer, reader->debugProperties)) { readResult = CONFIG_FILE_READER_HARD_FAIL; break; } } } /* Always free each line read. */ free(bufferW); } lineNumber++; } while (c != NULL); /* Close the file */ fclose(stream); return readResult; } /** * Reads configuration lines from the file `filename' and calls `callback' with the line and * `callbackParam' specified to its arguments. * * @param filename Name of configuration file to read. * @param fileRequired TRUE if the file specified by filename is required, FALSE if a missing * file will silently fail. * @param callback Pointer to a callback funtion which will be called for each line read. * @param callbackParam Pointer to additional user data which will be passed to the callback. * @param enableIncludes If TRUE then includes will be supported. * @param preload TRUE if this is being called in the preload step meaning that all errors * should be suppressed. * @param argCommand Argument passed to the binary. * @param originalWorkingDir Working directory of the binary at the moment it was launched. * @param warnedVarMap Map of undefined environment variables for which the user was warned. * @param logWarnings Flag that controls whether or not warnings will be logged. * @param logWarningLogLevel Log level at which any log warnings will be logged. * @param isDebugging Flag that controls whether or not debug output will be logged. * * @return CONFIG_FILE_READER_SUCCESS if the file was read successfully, * CONFIG_FILE_READER_FAIL if there were any problems at all, or * CONFIG_FILE_READER_HARD_FAIL if the problem should cascaded all the way up. */ int configFileReader(const TCHAR *filename, int fileRequired, ConfigFileReader_Callback callback, void *callbackParam, int enableIncludes, int preload, const TCHAR *argCommand, const TCHAR *originalWorkingDir, PHashMap warnedVarMap, int logWarnings, int logWarningLogLevel, int isDebugging) { ConfigFileReader reader; /* Initialize the reader. */ reader.callback = callback; reader.callbackParam = callbackParam; reader.enableIncludes = enableIncludes; reader.preload = preload; reader.debugIncludes = FALSE; reader.debugProperties = FALSE; return configFileReader_Read(&reader, filename, fileRequired, 0, NULL, 0, argCommand, originalWorkingDir, warnedVarMap, logWarnings, logWarningLogLevel, isDebugging); } wrapper_3.5.26_src/src/c/wrapper_file.h100644 0 0 6411 12440202301 15176 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * Author: * Tanuki Software Development Team */ #ifndef _WRAPPER_FILE_H #define _WRAPPER_FILE_H #ifdef WIN32 #include #endif #include "wrapper_i18n.h" #include "wrapper_hashmap.h" /*#define WRAPPER_FILE_DEBUG*/ /** * Tests whether a file exists. * * @return TRUE if exists, FALSE otherwise. */ extern int wrapperFileExists(const TCHAR * filename); #ifdef WIN32 extern int wrapperGetUNCFilePath(const TCHAR *path, int advice); #endif #ifdef WRAPPER_FILE_DEBUG extern void wrapperFileTests(); #endif /** * Callback declaration which can be passed to calls to configFileReader. */ typedef int (*ConfigFileReader_Callback)(void *param, const TCHAR *fileName, int lineNumber, TCHAR *config, int debugProperties); #define CONFIG_FILE_READER_SUCCESS 101 #define CONFIG_FILE_READER_FAIL 102 #define CONFIG_FILE_READER_HARD_FAIL 103 /** * Reads configuration lines from the file `filename' and calls `callback' with the line and * `callbackParam' specified to its arguments. * * @param filename Name of configuration file to read. * @param fileRequired TRUE if the file specified by filename is required, FALSE if a missing * file will silently fail. * @param callback Pointer to a callback funtion which will be called for each line read. * @param callbackParam Pointer to additional user data which will be passed to the callback. * @param enableIncludes If TRUE then includes will be supported. * @param preload TRUE if this is being called in the preload step meaning that all errors * should be suppressed. * @param argCommand Argument passed to the binary. * @param originalWorkingDir Working directory of the binary at the moment it was launched. * @param warnedVarMap Map of undefined environment variables for which the user was warned. * @param logWarnings Flag that controls whether or not warnings will be logged. * @param logWarningLogLevel Log level at which any log warnings will be logged. * @param isDebugging Flag that controls whether or not debug output will be logged. * * @return CONFIG_FILE_READER_SUCCESS if the file was read successfully, * CONFIG_FILE_READER_FAIL if there were any problems at all, or * CONFIG_FILE_READER_HARD_FAIL if the problem should cascaded all the way up. */ extern int configFileReader(const TCHAR *filename, int fileRequired, ConfigFileReader_Callback callback, void *callbackParam, int enableIncludes, int preload, const TCHAR *argCommand, const TCHAR *originalWorkingDir, PHashMap warnedVarMap, int logWarnings, int logWarningLogLevel, int isDebugging); #endif wrapper_3.5.26_src/src/c/wrapper_hashmap.c100644 0 0 31632 12440202301 15716 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #ifdef WIN32 #include #include #include #endif #include #include "wrapper_hashmap.h" #include "wrapper_i18n.h" #ifndef TRUE #define TRUE -1 #endif #ifndef FALSE #define FALSE 0 #endif /** * Compare two memory blocks. * * @param vA First memory block. * @param vALen Size of first memory block. * @param vB Second memory block. * @param vBLen Size of second memory block. * * @return -1 if vA is smaller, 0 if equal, 1 if vA is greater than vB. */ int memcmpHM(const void *vA, size_t vALen, const void *vB, size_t vBLen) { size_t i; unsigned char cA, cB; for (i = 0; (i < vALen) && (i < vBLen); i++) { cA = ((unsigned char *)vA)[i]; cB = ((unsigned char *)vB)[i]; if (cA < cB) { return -1; } else if (cA > cB) { return 1; } } /* Lengths are different. */ if (vALen < vBLen) { return -1; } else if (vALen > vBLen ) { return 1; } else { return 0; } } /** * Frees up any memory used by a HashMap. Any values returned from the HashMap will also * cease to be valid. * * @param hashMap HashMap to be freed. */ void freeHashMap(PHashMap hashMap) { int i; PHashBucket bucket; PHashEntry thisEntry; PHashEntry nextEntry; if (!hashMap) { return; } if (hashMap->buckets) { for (i = 0; i < hashMap->bucketCount; i++) { bucket = hashMap->buckets[i]; /* Free up the entries */ thisEntry = bucket->firstEntry; while (thisEntry) { nextEntry = thisEntry->nextEntry; /* Free up the entry. */ if (thisEntry->key) { free(thisEntry->key); } if (thisEntry->value) { free(thisEntry->value); } free(thisEntry); thisEntry = nextEntry; } /* Free up the bucket. */ free(bucket); } free(hashMap->buckets); } free(hashMap); } /** * Creates an empty HashMap with the specified number of buckets. * * @param bucketCount The number of buckets. The search within a bucket is * linear so it should be large enough to store all data * without too many items in each bucket. * * @return The new HashMap. */ PHashMap newHashMap(int bucketCount) { int i; PHashMap hashMap; PHashBucket bucket; /* Build up an empty HashMap. Be careful about clearing memory so a freeHashMap call will always work. */ hashMap = malloc(sizeof(HashMap)); if (!hashMap) { _tprintf(TEXT("Out of memory (%s)\n"), TEXT("NHM1")); return NULL; } memset(hashMap, 0, sizeof(HashMap)); hashMap->bucketCount = bucketCount; hashMap->buckets = malloc(sizeof(PHashBucket) * bucketCount); if (!hashMap->buckets) { _tprintf(TEXT("Out of memory (%s)\n"), TEXT("NHM2")); freeHashMap(hashMap); return NULL; } memset(hashMap->buckets, 0, sizeof(PHashBucket) * bucketCount); for (i = 0; i < hashMap->bucketCount; i++) { bucket = malloc(sizeof(HashBucket)); if (!bucket) { _tprintf(TEXT("Out of memory (%s)\n"), TEXT("NHM3")); freeHashMap(hashMap); return NULL; } memset(bucket, 0, sizeof(HashBucket)); hashMap->buckets[i] = bucket; } return hashMap; } /** * Calculate a bucketId based on the key. * * @param hashMap HashMap for which the bucket Id is being calculated. * @param key Key whose bucket Id is being calculated. * * @return The bucket Id. */ int getBucketId(PHashMap hashMap, const TCHAR *key) { size_t len = _tcslen(key); size_t i; TCHAR hash = 0; /* Loop over the characters and add all of the characters together. */ for (i = 0; i < len; i++) { hash = (hash + key[i]) & 0xffff; } return hash % hashMap->bucketCount; } /** * Puts a value into the HashMap. The key and value will both be cloned. * * @param hashMap HashMap to store the value into. * @param key The key to reference the value. * @param keySize The size of the key. * @param value The value to store. * @param valueSize The size of the value. * * @return TRUE if there were any problems. */ int hashMapPutKVVV(PHashMap hashMap, const void *key, size_t keySize, const void *value, size_t valueSize) { void *keyCopy; void *valueCopy; int bucketId; PHashBucket bucket; PHashEntry *thisEntryLoc; PHashEntry thisEntry; int cmp; PHashEntry newEntry; #ifdef _DEBUG_HASHMAP_DETAILED _tprintf(TEXT("hashMapPutKVVV(%p, %p, %d, %p, %d)\n"), hashMap, key, keySize, value, valueSize); #endif /* First create copies of the items being stored. */ keyCopy = malloc(keySize); if (!keyCopy) { _tprintf(TEXT("Out of memory (%s)\n"), TEXT("HMP1")); return TRUE; } memcpy(keyCopy, key, keySize); valueCopy = malloc(valueSize); if (!valueCopy) { _tprintf(TEXT("Out of memory (%s)\n"), TEXT("HMP2")); free(keyCopy); return TRUE; } memcpy(valueCopy, value, valueSize); /* Locate the bucket where the value should be stored. */ bucketId = getBucketId(hashMap, key); bucket = hashMap->buckets[bucketId]; #ifdef _DEBUG_HASHMAP_DETAILED _tprintf(TEXT(" keyCopy=%p, valueCopy=%p, bucketId=%d\n"), keyCopy, valueCopy, bucketId); #endif /* Figure out where in the bucket to store the value. */ thisEntryLoc = &(bucket->firstEntry); thisEntry = bucket->firstEntry; while (thisEntry) { cmp = memcmpHM(thisEntry->key, thisEntry->keySize, key, keySize); if (cmp > 0) { /* This entry's key is bigger, so we should be before it. */ newEntry = malloc(sizeof(HashEntry)); if (!newEntry) { _tprintf(TEXT("Out of memory (%s)\n"), TEXT("HMP3")); free(keyCopy); free(valueCopy); return TRUE; } newEntry->key = keyCopy; newEntry->keySize = keySize; newEntry->value = valueCopy; newEntry->valueSize = valueSize; newEntry->nextEntry = thisEntry; *thisEntryLoc = newEntry; bucket->size++; hashMap->size++; #ifdef _DEBUG_HASHMAP_DETAILED _tprintf(TEXT(" inserted entry -> bucketSize=%d hashMapSize=%d\n"), bucket->size, hashMap->size); #endif return FALSE; } else if (cmp == 0) { /* This is the exact same key so we are replacing the value. */ free(thisEntry->value); thisEntry->value = valueCopy; thisEntry->valueSize = valueSize; free(keyCopy); /* Not needed. */ #ifdef _DEBUG_HASHMAP_DETAILED _tprintf(TEXT(" replaced entry -> bucketSize=%d hashMapSize=%d\n"), bucket->size, hashMap->size); #endif return FALSE; } else { /* This entry's key is smaller so we should be after it. Keep looking. */ thisEntryLoc = &(thisEntry->nextEntry); thisEntry = thisEntry->nextEntry; } } /* If we get here then we need to append our value to the end. */ newEntry = malloc(sizeof(HashEntry)); if (!newEntry) { _tprintf(TEXT("Out of memory (%s)\n"), TEXT("HMP4")); free(keyCopy); free(valueCopy); return TRUE; } newEntry->key = keyCopy; newEntry->keySize = keySize; newEntry->value = valueCopy; newEntry->valueSize = valueSize; newEntry->nextEntry = NULL; /* This is the end. */ *thisEntryLoc = newEntry; bucket->size++; hashMap->size++; #ifdef _DEBUG_HASHMAP_DETAILED _tprintf(TEXT(" append entry -> bucketSize=%d hashMapSize=%d\n"), bucket->size, hashMap->size); #endif return FALSE; } /** * Puts a value into the HashMap. The key and value will both be cloned. * * @param hashMap HashMap to store the value into. * @param key The key to reference the value. * @param value The value to store. */ void hashMapPutKWVW(PHashMap hashMap, const TCHAR *key, const TCHAR *value) { size_t keySize = sizeof(TCHAR) * (_tcslen(key) + 1); size_t valueSize = sizeof(TCHAR) * (_tcslen(value) + 1); #ifdef _DEBUG_HASHMAP /* Can't use gtSTATIC here because of recursion. */ #if defined(UNICODE) && !defined(WIN32) _tprintf(TEXT("hashMapPutKWVW(map, \"%S\", \"%S\")\n"), key, value); #else _tprintf(TEXT("hashMapPutKWVW(map, \"%s\", \"%s\")\n"), key, value); #endif #endif hashMapPutKVVV(hashMap, key, keySize, value, valueSize); } /** * Puts a value into the HashMap. The key and value will both be cloned. * * @param hashMap HashMap to store the value into. * @param key The key to reference the value. * @param value The value to store. */ void hashMapPutKMBVW(PHashMap hashMap, const char *key, const TCHAR *value) { size_t keySize = sizeof(char) * (strlen(key) + 1); size_t valueSize = sizeof(TCHAR) * (_tcslen(value) + 1); hashMapPutKVVV(hashMap, key, keySize, value, valueSize); } /** * Gets a value from the HashMap. * * @param hashMap HashMap from which to lookup the value. * @param key Key of the value being looked up. * @param keySize Size of the key. * @param valueSize Pointer to a size_t which will store the size of the returned value if non-NULL. * * @return a reference to the value. It should not be modified or freed. */ const void *hashMapGetKVVV(PHashMap hashMap, const void *key, size_t keySize, size_t *valueSize) { int bucketId; PHashBucket bucket; PHashEntry thisEntry; int cmp; /* Initialize the return size. */ if (valueSize) { *valueSize = 0; } /* Locate the bucket where the value should be stored. */ bucketId = getBucketId(hashMap, key); bucket = hashMap->buckets[bucketId]; /* Figure out where in the bucket to store the value. */ thisEntry = bucket->firstEntry; while (thisEntry) { cmp = memcmpHM(thisEntry->key, thisEntry->keySize, key, keySize); if (cmp > 0) { /* This entry's key is bigger, so we are past where it should be. */ return NULL; } else if (cmp == 0) { /* This is the value we were looking for. */ if (valueSize) { *valueSize = thisEntry->valueSize; } return thisEntry->value; } else { /* Not yet. */ thisEntry = thisEntry->nextEntry; } } /* We didn't find it. */ return NULL; } /** * Gets a value from the HashMap. * * @param hashMap HashMap from which to lookup the value. * @param key Key of the value being looked up. * * @return a reference to the value. It should not be modified or freed. */ const TCHAR *hashMapGetKWVW(PHashMap hashMap, const TCHAR *key) { size_t keySize = sizeof(TCHAR) * (_tcslen(key) + 1); return (const TCHAR *)hashMapGetKVVV(hashMap, key, keySize, NULL); } /** * Gets a value from the HashMap. * * @param hashMap HashMap from which to lookup the value. * @param key Key of the value being looked up. * * @return a reference to the value. It should not be modified or freed. */ const TCHAR *hashMapGetKMBVW(PHashMap hashMap, const char *key) { size_t keySize = sizeof(char) * (strlen(key) + 1); return (const TCHAR *)hashMapGetKVVV(hashMap, key, keySize, NULL); } #ifdef _DEBUG_HASHMAP /** * Dumps the statistics of a HashMap. */ void dumpHashMapStats(PHashMap hashMap) { int i; #ifdef _DEBUG_HASHMAP_DETAILED int j; PHashEntry entry; #endif _tprintf(TEXT("HashMap: %p\n"), hashMap); _tprintf(TEXT(" size: %d\n"), hashMap->size); _tprintf(TEXT(" bucketCount: %d\n"), hashMap->bucketCount); if (hashMap->buckets) { for (i = 0; i < hashMap->bucketCount; i++) { PHashBucket bucket = hashMap->buckets[i]; if (bucket) { _tprintf(TEXT(" bucket[%d]: size: %d\n"), i, bucket->size); #ifdef _DEBUG_HASHMAP_DETAILED j = 0; entry = bucket->firstEntry; while (entry) { _tprintf(TEXT(" entry[%d]: key=%p (size=%d) value=%p (size=%d)\n"), j, entry->key, entry->keySize, entry->value, entry->valueSize); entry = entry->nextEntry; j++; } #endif } else { _tprintf(TEXT(" bucket[%d]: NULL\n"), i); } } } } #endif wrapper_3.5.26_src/src/c/wrapper_hashmap.h100644 0 0 7225 12440202301 15704 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #ifndef _WRAPPER_HASHMAP #define _WRAPPER_HASHMAP /*#define _DEBUG_HASHMAP */ /*#define _DEBUG_HASHMAP_DETAILED*/ #include "wrapper_i18n.h" typedef struct HashEntry HashEntry, *PHashEntry; struct HashEntry { size_t keySize; void *key; size_t valueSize; void *value; PHashEntry nextEntry; }; typedef struct { int size; PHashEntry firstEntry; } HashBucket, *PHashBucket; typedef struct { int bucketCount; int size; PHashBucket *buckets; } HashMap, *PHashMap; /** * Frees up any memory used by a HashMap. Any values returned from the HashMap will also * cease to be valid. * * @param hashMap HashMap to be freed. */ extern void freeHashMap(PHashMap hashMap); /** * Creates an empty HashMap with the specified number of buckets. * * @param bucketCount The number of buckets. The search within a bucket is * linear so it should be large enough to store all data * without too many items in each bucket. * * @return The new HashMap. */ extern PHashMap newHashMap(int bucketCount); /** * Puts a value into the HashMap. The key and value will both be cloned. * * @param hashMap HashMap to store the value into. * @param key The key to reference the value. * @param keySize The size of the key. * @param value The value to store. * @param valueSize The size of the value. * * @return TRUE if there were any problems. */ extern int hashMapPutKVVV(PHashMap hashMap, const void *key, size_t keySize, const void *value, size_t valueSize); /** * Puts a value into the HashMap. The key and value will both be cloned. * * @param hashMap HashMap to store the value into. * @param key The key to reference the value. * @param value The value to store. */ extern void hashMapPutKWVW(PHashMap hashMap, const TCHAR *key, const TCHAR *value); /** * Puts a value into the HashMap. The key and value will both be cloned. * * @param hashMap HashMap to store the value into. * @param key The key to reference the value. * @param value The value to store. */ extern void hashMapPutKMBVW(PHashMap hashMap, const char *key, const TCHAR *value); /** * Gets a value from the HashMap. * * @param hashMap HashMap from which to lookup the value. * @param key Key of the value being looked up. * @param keySize Size of the key. * @param valueSize Pointer to a size_t which will store the size of the returned value if non-NULL. * * @return a reference to the value. It should not be modified or freed. */ extern const void *hashMapGetKVVV(PHashMap hashMap, const void *key, size_t keySize, size_t *valueSize); /** * Gets a value from the HashMap. * * @param hashMap HashMap from which to lookup the value. * @param key Key of the value being looked up. * * @return a reference to the value. It should not be modified or freed. */ extern const TCHAR *hashMapGetKWVW(PHashMap hashMap, const TCHAR *key); /** * Gets a value from the HashMap. * * @param hashMap HashMap from which to lookup the value. * @param key Key of the value being looked up. * * @return a reference to the value. It should not be modified or freed. */ extern const TCHAR *hashMapGetKMBVW(PHashMap hashMap, const char *key); #ifdef _DEBUG_HASHMAP /** * Dumps the statistics of a HashMap. */ extern void dumpHashMapStats(PHashMap hashMap); #endif #endif wrapper_3.5.26_src/src/c/wrapper_i18n.c100644 0 0 123310 12440202301 15067 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #ifdef WIN32 #include #include #else #ifndef FREEBSD #include #endif #include #include #include #endif #include #include #include #include #include #include "logger_base.h" #if defined(IRIX) #define PATH_MAX FILENAME_MAX #endif #ifndef TRUE #define TRUE -1 #endif #ifndef FALSE #define FALSE 0 #endif /** * Dynamically load the symbols for the iconv library */ #ifdef FREEBSD typedef void *iconv_t; static iconv_t (*wrapper_iconv_open)(const char *, const char *); static size_t (*wrapper_iconv)(iconv_t, const char **, size_t *, char **, size_t *); static int (*wrapper_iconv_close)(iconv_t); #else #define wrapper_iconv_open iconv_open #define wrapper_iconv iconv #define wrapper_iconv_close iconv_close #endif #if defined(UNICODE) && defined(WIN32) /** * @param multiByteChars The MultiByte encoded source string. * @param encoding Encoding of the MultiByte characters. * @param outputBuffer If return is TRUE then this will be an error message. If return is FALSE then this will contain the * requested WideChars string. If there were any memory problems, the return will be TRUE and the * buffer will be set to NULL. In any case, it is the responsibility of the caller to free the output * buffer memory. * @param localizeErrorMessage TRUE if the error message can be localized. * * @return TRUE if there were problems, FALSE if Ok. * */ int multiByteToWideChar(const char *multiByteChars, int encoding, TCHAR **outputBufferW, int localizeErrorMessage) { const TCHAR *errorTemplate; size_t errorTemplateLen; int req; /* Clear the output buffer as a sanity check. Shouldn't be needed. */ *outputBufferW = NULL; req = MultiByteToWideChar(encoding, MB_ERR_INVALID_CHARS, multiByteChars, -1, NULL, 0); if (req <= 0) { if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { errorTemplate = (localizeErrorMessage ? TEXT("Invalid multibyte sequence.") : TEXT("Invalid multibyte sequence.")); errorTemplateLen = _tcslen(errorTemplate) + 1; *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, TEXT("%s"), errorTemplate); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; } else { errorTemplate = (localizeErrorMessage ? TEXT("Unexpected conversion error: %d") : TEXT("Unexpected conversion error: %d")); errorTemplateLen = _tcslen(errorTemplate) + 10 + 1; *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, GetLastError()); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; } } *outputBufferW = malloc((req + 1) * sizeof(TCHAR)); if (!(*outputBufferW)) { _tprintf(TEXT("Out of memory (%s%02d)"), TEXT("MBTWC"), 1); /* Out of memory. *outputBufferW already NULL. */ return TRUE; } MultiByteToWideChar(encoding, MB_ERR_INVALID_CHARS, multiByteChars, -1, *outputBufferW, req + 1); return FALSE; } #endif #if defined(UNICODE) && !defined(WIN32) #include /** * Converts a MultiByte encoded string to a WideChars (UNICODE/Locale dependant) string. * * @param multiByteChars The MultiByte encoded source string. * @param multiByteEncoding The source encoding. * @param interumEncoding The interum encoding before transforming to Wide Chars (On solaris this is the result encoding.) * If the ecoding is appended by "//TRANSLIT", "//IGNORE", "//TRANSLIT//IGNORE" then the conversion * will try to transliterate and or ignore invalid characters without warning. * @param outputBufferW If return is TRUE then this will be an error message. If return is FALSE then this will contain the * requested WideChars string. If there were any memory problems, the return will be TRUE and the * buffer will be set to NULL. In any case, it is the responsibility of the caller to free the output * buffer memory. * @param localizeErrorMessage TRUE if the error message can be localized. * * @return TRUE if there were problems, FALSE if Ok. */ int multiByteToWideChar(const char *multiByteChars, const char *multiByteEncoding, char *interumEncoding, wchar_t **outputBufferW, int localizeErrorMessage) { const TCHAR *errorTemplate; size_t errorTemplateLen; size_t iconv_value; char *nativeCharStart; char *nativeCharStartCopy; size_t multiByteCharsLen; size_t nativeCharLen; size_t nativeCharLenCopy; size_t multiByteCharsLenStart; #if defined(FREEBSD) || defined(SOLARIS) || defined(AIX) const char* multiByteCharsStart; #else char* multiByteCharsStart; #endif iconv_t conv_desc; int didIConv; int redoIConv; size_t wideCharLen; /* Clear the output buffer as a sanity check. Shouldn't be needed. */ *outputBufferW = NULL; /* First we need to convert from the multi-byte string to native. */ /* If the multiByteEncoding and interumEncoding encodings are equal then there is nothing to do. */ if (strcmp(multiByteEncoding, interumEncoding) != 0 && strcmp(interumEncoding, "646") != 0) { conv_desc = wrapper_iconv_open(interumEncoding, multiByteEncoding); /* convert multiByte encoding to interum-encoding*/ if (conv_desc == (iconv_t)(-1)) { /* Initialization failure. */ if (errno == EINVAL) { errorTemplate = (localizeErrorMessage ? TEXT("Conversion from '% s' to '% s' is not supported.") : TEXT("Conversion from '% s' to '% s' is not supported.")); errorTemplateLen = _tcslen(errorTemplate) + strlen(multiByteEncoding) + strlen(interumEncoding) + 1; *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, multiByteEncoding, interumEncoding); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; } else { errorTemplate = (localizeErrorMessage ? TEXT("Initialization failure in iconv: %d") : TEXT("Initialization failure in iconv: %d")); errorTemplateLen = _tcslen(errorTemplate) + 10 + 1; *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, errno); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; } } multiByteCharsLen = strlen(multiByteChars); if (!multiByteCharsLen) { /* The input string is empty, so the output will be as well. */ *outputBufferW = malloc(sizeof(TCHAR)); if (*outputBufferW) { (*outputBufferW)[0] = TEXT('\0'); return FALSE; } else { /* Out of memory. *outputBufferW already NULL. */ return TRUE; } } ++multiByteCharsLen; /* add 1 in order to store \0 - especially necessary in UTF-8 -> UTF-8 conversions*/ /* We need to figure out how many bytes we need to store the native encoded string. */ nativeCharLen = multiByteCharsLen; nativeCharStart = NULL; do { redoIConv = FALSE; if (nativeCharStart) { free(nativeCharStart); } multiByteCharsLenStart = multiByteCharsLen; #if defined(FREEBSD) || defined(SOLARIS) || defined(AIX) multiByteCharsStart = multiByteChars; #else multiByteCharsStart = (char *)multiByteChars; #endif nativeCharStart = malloc(nativeCharLen); if (!nativeCharStart) { /* Out of memory. */ *outputBufferW = NULL; return TRUE; } /* Make a copy of the nativeCharLen as this call will replace it with the number of chars used. */ nativeCharLenCopy = nativeCharLen; nativeCharStartCopy = nativeCharStart; iconv_value = wrapper_iconv(conv_desc, &multiByteCharsStart, &multiByteCharsLenStart, &nativeCharStartCopy, &nativeCharLenCopy); /* Handle failures. */ if (iconv_value == (size_t)-1) { /* See "man 3 iconv" for an explanation. */ switch (errno) { case EILSEQ: free(nativeCharStart); errorTemplate = (localizeErrorMessage ? TEXT("Invalid multibyte sequence.") : TEXT("Invalid multibyte sequence.")); errorTemplateLen = _tcslen(errorTemplate) + 1; *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; case EINVAL: free(nativeCharStart); errorTemplate = (localizeErrorMessage ? TEXT("Incomplete multibyte sequence.") : TEXT("Incomplete multibyte sequence.")); errorTemplateLen = _tcslen(errorTemplate) + 1; *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; case E2BIG: /* native char buffer was too small, extend buffer and redo */ nativeCharLen += multiByteCharsLen; redoIConv = TRUE; break; default: free(nativeCharStart); errorTemplate = (localizeErrorMessage ? TEXT("Unexpected iconv error: %d") : TEXT("Unexpected iconv error: %d")); errorTemplateLen = _tcslen(errorTemplate) + 10 + 1; *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, errno); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; } } } while (redoIConv); /* finish iconv */ if (wrapper_iconv_close(conv_desc)) { free(nativeCharStart); errorTemplate = (localizeErrorMessage ? TEXT("Cleanup failure in iconv: %d") : TEXT("Cleanup failure in iconv: %d")); errorTemplateLen = _tcslen(errorTemplate) + 10 + 1; *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, errno); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; } didIConv = TRUE; } else { nativeCharStart = (char *)multiByteChars; didIConv = FALSE; } /* now store the result into a wchar_t */ wideCharLen = mbstowcs(NULL, nativeCharStart, MBSTOWCS_QUERY_LENGTH); if (wideCharLen == (size_t)-1) { if (didIConv) { free(nativeCharStart); } if (errno == EILSEQ) { errorTemplate = (localizeErrorMessage ? TEXT("Invalid multibyte sequence.") : TEXT("Invalid multibyte sequence.")); errorTemplateLen = _tcslen(errorTemplate) + 1; } else { errorTemplate = (localizeErrorMessage ? TEXT("Unexpected iconv error: %d") : TEXT("Unexpected iconv error: %d")); errorTemplateLen = _tcslen(errorTemplate) + 10 + 1; } *outputBufferW = malloc(sizeof(TCHAR) * errorTemplateLen); if (*outputBufferW) { _sntprintf(*outputBufferW, errorTemplateLen, errorTemplate, errno); } else { /* Out of memory. *outputBufferW already NULL. */ } return TRUE; } *outputBufferW = malloc(sizeof(wchar_t) * (wideCharLen + 1)); if (!(*outputBufferW)) { /* Out of memory. *outputBufferW already NULL. */ if (didIConv) { free(nativeCharStart); } return TRUE; } mbstowcs(*outputBufferW, nativeCharStart, wideCharLen + 1); (*outputBufferW)[wideCharLen] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ /* free the native char */ if (didIConv) { free(nativeCharStart); } return FALSE; } size_t _treadlink(TCHAR* exe, TCHAR* fullPath, size_t size) { char* cExe; char* cFullPath; size_t req; req = wcstombs(NULL, exe, 0); if (req == (size_t)-1) { return (size_t)-1; } cExe = malloc(req + 1); if (cExe) { wcstombs(cExe, exe, req + 1); cFullPath = malloc(size); if (cFullPath) { req = readlink(cExe, cFullPath, size); if (req == (size_t)-1) { free(cFullPath); free(cExe); return (size_t)-1; } req = mbstowcs(fullPath, cFullPath, size); if (req == (size_t)-1) { free(cFullPath); free(cExe); return (size_t)-1; } fullPath[size - 1] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ free(cFullPath); free(cExe); return req * sizeof(TCHAR); } else { free(cExe); } } return (size_t)-1; } /** * This Wrapper function internally does a malloc to generate the * Wide-char version of the return string. This must be freed by the caller. */ TCHAR* _tgetcwd(TCHAR *buf, size_t size) { char* cBuf; size_t len; if (buf) { cBuf = malloc(size); if (cBuf) { if (getcwd(cBuf, size) != NULL) { len = mbstowcs(buf, cBuf, size); if (len == (size_t)-1) { /* Failed. */ free(cBuf); return NULL; } buf[size - 1] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ free(cBuf); return buf; } free(cBuf); } } return NULL; } long _tpathconf(const TCHAR *path, int name) { char* cPath; size_t req; long retVal; req = wcstombs(NULL, path, 0); if (req == (size_t)-1) { return -1; } cPath = malloc(req + 1); if (cPath) { wcstombs(cPath, path, req + 1); retVal = pathconf(cPath, name); free(cPath); return retVal; } return -1; } /** * Set the current locale. * * This Wrapper function internally does a malloc to generate the * Wide-char version of the return string. This must be freed by the caller. * * @param category * @param locale The requested locale. TEXT("") for the default. * * @return NULL if there are any errors, otherwise return locale. */ TCHAR *_tsetlocale(int category, const TCHAR *locale) { char* cLocale; char* cReturn; TCHAR* tReturn; size_t req; req = wcstombs(NULL, locale, 0); if (req == (size_t)-1) { return NULL; } cLocale = malloc(sizeof(char) * (req + 1)); if (cLocale) { wcstombs(cLocale, locale, req + 1); cReturn = setlocale(category, cLocale); free(cLocale); if (cReturn) { req = mbstowcs(NULL, cReturn, MBSTOWCS_QUERY_LENGTH); if (req != (size_t)-1) { tReturn = malloc(sizeof(TCHAR) * (req + 1)); if (tReturn) { mbstowcs(tReturn, cReturn, req + 1); tReturn[req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ return tReturn; } } } } return NULL; } int _tprintf(const wchar_t *fmt,...) { int i, flag; wchar_t *msg; va_list args; if (wcsstr(fmt, TEXT("%s")) != NULL) { msg = malloc(sizeof(wchar_t) * (wcslen(fmt) + 1)); if (msg) { wcsncpy(msg, fmt, wcslen(fmt) + 1); for (i = 0; i < wcslen(fmt); i++){ if (fmt[i] == TEXT('%') && i < wcslen(fmt) && fmt[i + 1] == TEXT('s') && (i == 0 || fmt[i - 1] != TEXT('%'))) { msg[i + 1] = TEXT('S'); i++; } } msg[wcslen(fmt)] = TEXT('\0'); } flag = TRUE; } else { msg = (wchar_t*)fmt; flag = FALSE; } if (msg) { va_start(args, fmt); i = vwprintf(msg, args); va_end (args); if (flag == TRUE) { free(msg); } return i; } return -1; } int _ftprintf(FILE *stream, const wchar_t *fmt, ...) { int i, flag; wchar_t *msg; va_list args; if (wcsstr(fmt, TEXT("%s")) != NULL) { msg = malloc(sizeof(wchar_t) * (wcslen(fmt) + 1)); if (msg) { wcsncpy(msg, fmt, wcslen(fmt) + 1); for (i = 0; i < wcslen(fmt); i++){ if (fmt[i] == TEXT('%') && i < wcslen(fmt) && fmt[i + 1] == TEXT('s') && (i == 0 || fmt[i - 1] != TEXT('%'))) { msg[i + 1] = TEXT('S'); i++; } } msg[wcslen(fmt)] = TEXT('\0'); } flag = TRUE; } else { msg = (wchar_t*)fmt; flag = FALSE; } if (msg) { va_start(args, fmt); i = vfwprintf(stream, msg, args); va_end (args); if (flag == TRUE) { free(msg); } return i; } return -1; } int _sntprintf(TCHAR *str, size_t size, const TCHAR *fmt, ...) { int i, flag; wchar_t *msg; va_list args; if (wcsstr(fmt, TEXT("%s")) != NULL) { msg = malloc(sizeof(wchar_t) * (wcslen(fmt) + 1)); if (msg) { wcsncpy(msg, fmt, wcslen(fmt) + 1); for (i = 0; i < wcslen(fmt); i++){ if (fmt[i] == TEXT('%') && i < wcslen(fmt) && fmt[i + 1] == TEXT('s') && (i == 0 || fmt[i - 1] != TEXT('%'))) { msg[i + 1] = TEXT('S'); i++; } } msg[wcslen(fmt)] = TEXT('\0'); } flag = TRUE; } else { msg = (wchar_t*)fmt; flag = FALSE; } if (msg) { va_start(args, fmt); i = vswprintf(str, size, msg, args); va_end (args); if (flag == TRUE) { free(msg); } return i; } return -1; } int _tremove(const TCHAR *path) { char* cPath; size_t req; int result; req = wcstombs(NULL, path, 0); if (req == (size_t)-1) { return -1; } cPath = malloc(req + 1); if (cPath) { wcstombs(cPath, path, req + 1); result = remove(cPath); free(cPath); return result; } return -1; } int _trename(const TCHAR *path, const TCHAR *to) { char* cPath; char* cTo; size_t req; int ret; ret = -1; req = wcstombs(NULL, path, 0); if (req == (size_t)-1) { return ret; } cPath = malloc(req + 1); if (cPath) { wcstombs(cPath, path, req + 1); req = wcstombs(NULL, to, 0); if (req == (size_t)-1) { free(cPath); return ret; } cTo = malloc(req + 1); if (cTo) { wcstombs(cTo, to, req + 1); ret = rename(cPath, cTo); free(cTo); } free(cPath); } return ret; } void _tsyslog(int priority, const TCHAR *message) { char* cMessage; size_t req; req = wcstombs(NULL, message, 0); if (req == (size_t)-1) { return; } cMessage = malloc(req + 1); if (cMessage) { wcstombs(cMessage, message, req + 1); syslog(priority, "%s", cMessage); free(cMessage); } } /** * This Wrapper function internally does a malloc to generate the * Wide-char version of the return string. This must be freed by the caller. * Only needed inside the following: * #if !defined(WIN32) && defined(UNICODE) * #endif */ TCHAR * _tgetenv( const TCHAR * name ) { char* cName; TCHAR* val; size_t req; char *cVal; req = wcstombs(NULL, name, 0); if (req == (size_t)-1) { return NULL; } cName = malloc(sizeof(char) * (req + 1)); if (cName) { wcstombs(cName, name, req + 1); cVal = getenv(cName); free(cName); if (cVal == NULL) { return NULL; } req = mbstowcs(NULL, cVal, MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { /* Failed. */ return NULL; } val = malloc(sizeof(TCHAR) * (req + 1)); if (val) { mbstowcs(val, cVal, req + 1); val[req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ return val; } } return NULL; } FILE* _tfopen(const wchar_t* file, const wchar_t* mode) { int sizeFile, sizeMode; char* cFile; char* cMode; FILE *f = NULL; sizeFile = wcstombs(NULL, (wchar_t*)file, 0); if (sizeFile == (size_t)-1) { return NULL; } cFile= malloc(sizeFile + 1); if (cFile) { wcstombs(cFile, (wchar_t*) file, sizeFile + 1); sizeMode = wcstombs(NULL, (wchar_t*)mode, 0); if (sizeMode == (size_t)-1) { free(cFile); return NULL; } cMode= malloc(sizeMode + 1); if (cMode) { wcstombs(cMode, (wchar_t*) mode, sizeMode + 1); f = fopen(cFile, cMode); free(cMode); } free(cFile); } return f; } int _tunlink(const wchar_t* address) { int size; char *cAddress; size = wcstombs(NULL, (wchar_t*)address, 0); if (size == (size_t)-1) { return -1; } cAddress= malloc(size + 1); if (cAddress) { wcstombs(cAddress, (wchar_t*) address, size + 1); size = unlink(cAddress); free(cAddress); return size; } return -1; } int _tmkfifo(TCHAR* arg, mode_t mode) { size_t size; char *cStr; int r; r = -1; size = wcstombs(NULL, arg, 0); if (size == (size_t)-1) { return r; } cStr = malloc(size + 1); if (cStr) { wcstombs(cStr, arg, size + 1); r = mkfifo(cStr, mode); free(cStr); } return r; } int _tchdir(const TCHAR *path) { int r; size_t size; char *cStr; r = -1; size = wcstombs(NULL, path, 0); if (size == (size_t)-1) { return r; } cStr = malloc(size + 1); if (cStr) { wcstombs(cStr, path, size + 1); r = chdir(cStr); free(cStr); } return r; } int _texecvp(TCHAR* arg, TCHAR **cmd) { char** cCmd; char *cArg; int i, size; size_t req; for (i = 0; cmd[i] != NULL; i++) { ; } size = i; cCmd = malloc((i + 1) * sizeof *cCmd); if (cCmd) { for (i = 0; i < size; i++) { req = wcstombs(NULL, cmd[i], 0); if (req == (size_t)-1) { i--; for (; i > 0; i--) { free(cCmd[i]); } free(cCmd); return -1; } cCmd[i] = malloc(req + 1); if (cCmd[i]) { wcstombs(cCmd[i], cmd[i], req + 1); } else { i--; for (; i > 0; i--) { free(cCmd[i]); } free(cCmd); return -1; } } cCmd[size] = '\0'; req = wcstombs(NULL, arg, 0); if (req == (size_t)-1) { for (; size >= 0; size--) { free(cCmd[size]); } free(cCmd); return -1; } cArg = malloc(req + 1); if (cArg) { wcstombs(cArg, arg, req + 1); i = execvp(cArg, cCmd); free(cArg); } else { i = -1; } for (; size >= 0; size--) { free(cCmd[size]); } free(cCmd); return i; } return -1; } #ifdef ECSCASECMP int wcscasecmp(const wchar_t* s1, const wchar_t* s2) { wint_t a1, a2; if (s1 == s2) { return 0; } do { a1 = towlower(*s1++); a2 = towlower(*s2++); if (a1 == L'\0') { break; } } while (a1 == a2); return a1 - a2; } #endif #if defined(HPUX) int _vsntprintf(wchar_t *ws, size_t n, const wchar_t *format, va_list arg) { /* z/OS shows unexpected behaviour if the format string is empty */ if (ws) { ws[0] = TEXT('\0'); } return vswprintf(ws, n, format, arg); } #endif int _texecve(TCHAR* arg, TCHAR **cmd, TCHAR** env) { char **cCmd; char *cArg; char **cEnv; int i, sizeCmd, sizeEnv; size_t req; for (i = 0; cmd[i] != NULL; i++) { ; } sizeCmd = i; cCmd = malloc((i + 1) * sizeof *cCmd); if (cCmd) { for (i = 0; i < sizeCmd; i++) { req = wcstombs(NULL, cmd[i], 0); if (req == (size_t)-1) { i--; for (; i > 0; i--) { free(cCmd[i]); } free(cCmd); return -1; } cCmd[i] = malloc(req + 1); if (cCmd[i]) { wcstombs(cCmd[i], cmd[i], req + 1); } else { i--; for (; i > 0; i--) { free(cCmd[i]); } free(cCmd); return -1; } } cCmd[sizeCmd] = '\0'; for (i = 0; env[i] != TEXT('\0'); i++) { ; } sizeEnv = i; cEnv = malloc((i + 1) * sizeof *cEnv); if (!cEnv) { for (; sizeCmd >= 0; sizeCmd--) { free(cCmd[sizeCmd]); } free(cCmd); return -1; } for (i = 0; i < sizeEnv; i++) { req = wcstombs(NULL, env[i], 0); if (req == (size_t)-1) { i--; for (; i > 0; i--) { free(cEnv[i]); } free(cEnv); for (; sizeCmd >= 0; sizeCmd--) { free(cCmd[sizeCmd]); } free(cCmd); return -1; } cEnv[i] = malloc(req + 1); if (cEnv[i]) { wcstombs(cEnv[i], env[i], req + 1); } else { i--; for (; i > 0; i--) { free(cEnv[i]); } free(cEnv); for (; sizeCmd >= 0; sizeCmd--) { free(cCmd[sizeCmd]); } free(cCmd); return -1; } } cEnv[sizeEnv] = '\0'; req = wcstombs(NULL, arg, 0); if (req == (size_t)-1) { for (; sizeEnv >= 0; sizeEnv--) { free(cEnv[sizeEnv]); } free(cEnv); for (; sizeCmd >= 0; sizeCmd--) { free(cCmd[sizeCmd]); } free(cCmd); return -1; } cArg = malloc(req + 1); if (cArg) { wcstombs(cArg, arg, req + 1); i = execve(cArg, cCmd, cEnv); free(cArg); } else { i = -1; } for (; sizeEnv >= 0; sizeEnv--) { free(cEnv[sizeEnv]); } free(cEnv); for (; sizeCmd >= 0; sizeCmd--) { free(cCmd[sizeCmd]); } free(cCmd); return i; } return -1; } int _topen(const TCHAR *path, int oflag, mode_t mode) { char* cPath; int r; size_t size; size = wcstombs(NULL, path, 0); if (size == (size_t)-1) { return -1; } cPath = malloc(size + 1); if (cPath) { wcstombs(cPath, path, size + 1); r = open(cPath, oflag, mode); free(cPath); return r; } return -1; } #if defined(WRAPPER_USE_PUTENV) /** * Normal calls to putenv do not free the string parameter, but UNICODE calls can and should. */ int _tputenv(const TCHAR *string) { int r; size_t size; char *cStr; size = wcstombs(NULL, (wchar_t*)string, 0); if (size == (size_t)-1) { return -1; } cStr = malloc(size + 1); if (cStr) { wcstombs(cStr, string, size + 1); r = putenv(cStr); /* Can't free cStr as it becomes part of the environment. */ /* free(cstr); */ return r; } return -1; } #else int _tsetenv(const TCHAR *name, const TCHAR *value, int overwrite) { int r = -1; size_t size; char *cName; char *cValue; size = wcstombs(NULL, (wchar_t*)name, 0); if (size == (size_t)-1) { return -1; } cName = malloc(size + 1); if (cName) { wcstombs(cName, name, size + 1); size = wcstombs(NULL, (wchar_t*)value, 0); if (size == (size_t)-1) { free(cName); return -1; } cValue = malloc(size + 1); if (cValue) { wcstombs(cValue, value, size + 1); r = setenv(cName, cValue, overwrite); free(cValue); } free(cName); } return r; } void _tunsetenv(const TCHAR *name) { size_t size; char *cName; size = wcstombs(NULL, (wchar_t*)name, 0); if (size == (size_t)-1) { return; } cName = malloc(size + 1); if (cName) { wcstombs(cName, name, size + 1); unsetenv(cName); free(cName); } } #endif int _tstat(const wchar_t* filename, struct stat *buf) { int size; char *cFileName; size = wcstombs(NULL, (wchar_t*)filename, 0); if (size == (size_t)-1) { return -1; } cFileName = malloc(size + 1); if (cFileName) { wcstombs(cFileName, (wchar_t*) filename, size + 1); size = stat(cFileName, buf); free(cFileName); } return size; } /** * @param fileName The file name to be resolved. * @param resolvedName A buffer large enough to hold the expanded path. * @param resolvedNameSize The size of the resolvedName buffer, should usually be PATH_MAX + 1. * * @return resolvedName if successful, otherwise NULL. */ wchar_t* _trealpathN(const wchar_t* fileName, wchar_t *resolvedName, size_t resolvedNameSize) { char *cFile; #if defined(IRIX) char resolved[FILENAME_MAX + 1]; #else char resolved[PATH_MAX + 1]; #endif int sizeFile; int req; char* returnVal; /* Initialize the return value. */ resolvedName[0] = TEXT('\0'); sizeFile = wcstombs(NULL, fileName, 0); if (sizeFile == (size_t)-1) { return NULL; } cFile = malloc(sizeFile + 1); if (cFile) { wcstombs(cFile, fileName, sizeFile + 1); /* get the canonicalized absolute pathname */ returnVal = realpath(cFile, resolved); free(cFile); /** * In case realpath failed, resolved may contain a part of the path (until the folder that is invalid). So we convert it anyway. * For example cFile is "/home/user/alex/../nina" and in fact "/home/user/nina" doesn't exist. * So realpath will fail and resolved will be "/home/user" */ req = mbstowcs(NULL, resolved, MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { resolvedName[0] = TEXT('\0'); /* Terminate the output buffer as it does not contain a path. */ return NULL; } mbstowcs(resolvedName, resolved, resolvedNameSize); resolvedName[resolvedNameSize - 1] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ if (returnVal == NULL) { return NULL; } else { return resolvedName; } } return NULL; } #endif /** * Function to get the system encoding name/number for the encoding * of the conf file * * @para String holding the encoding from the conf file * * @return TRUE if not found, FALSE otherwise * */ #ifdef WIN32 int getEncodingByName(char* encodingMB, int *encoding) { #else int getEncodingByName(char* encodingMB, char** encoding) { #endif if (strIgnoreCaseCmp(encodingMB, "Shift_JIS") == 0) { #if defined(FREEBSD) || defined (AIX) || defined(MACOSX) *encoding = "SJIS"; #elif defined(WIN32) *encoding = 932; #else *encoding = "shiftjis"; #endif } else if (strIgnoreCaseCmp(encodingMB, "eucJP") == 0) { #if defined(AIX) *encoding = "IBM-eucJP"; #elif defined(WIN32) *encoding = 20932; #else *encoding = "eucJP"; #endif } else if (strIgnoreCaseCmp(encodingMB, "UTF-8") == 0) { #if defined(HPUX) *encoding = "utf8"; #elif defined(WIN32) *encoding = 65001; #else *encoding = "UTF-8"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-1") == 0) { #if defined(WIN32) *encoding = 28591; #elif defined(LINUX) *encoding = "ISO-8859-1"; #else *encoding = "ISO8859-1"; #endif } else if (strIgnoreCaseCmp(encodingMB, "CP1252") == 0) { #if defined(WIN32) *encoding = 1252; #else *encoding = "CP1252"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-2") == 0) { #if defined(WIN32) *encoding = 28592; #elif defined(LINUX) *encoding = "ISO-8859-2"; #else *encoding = "ISO8859-2"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-3") == 0) { #if defined(WIN32) *encoding = 28593; #elif defined(LINUX) *encoding = "ISO-8859-3"; #else *encoding = "ISO8859-3"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-4") == 0) { #if defined(WIN32) *encoding = 28594; #elif defined(LINUX) *encoding = "ISO-8859-4"; #else *encoding = "ISO8859-4"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-5") == 0) { #if defined(WIN32) *encoding = 28595; #elif defined(LINUX) *encoding = "ISO-8859-5"; #else *encoding = "ISO8859-5"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-6") == 0) { #if defined(WIN32) *encoding = 28596; #elif defined(LINUX) *encoding = "ISO-8859-6"; #else *encoding = "ISO8859-6"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-7") == 0) { #if defined(WIN32) *encoding = 28597; #elif defined(LINUX) *encoding = "ISO-8859-7"; #else *encoding = "ISO8859-7"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-8") == 0) { #if defined(WIN32) *encoding = 28598; #elif defined(LINUX) *encoding = "ISO-8859-8"; #else *encoding = "ISO8859-8"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-9") == 0) { #if defined(WIN32) *encoding = 28599; #elif defined(LINUX) *encoding = "ISO-8859-9"; #else *encoding = "ISO8859-9"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-10") == 0) { #if defined(WIN32) *encoding = 28600; #elif defined(LINUX) *encoding = "ISO-8859-10"; #else *encoding = "ISO8859-10"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-11") == 0) { #if defined(WIN32) *encoding = 28601; #elif defined(LINUX) *encoding = "ISO-8859-11"; #else *encoding = "ISO8859-11"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-13") == 0) { #if defined(WIN32) *encoding = 28603; #elif defined(LINUX) *encoding = "ISO-8859-13"; #else *encoding = "ISO8859-13"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-14") == 0) { #if defined(WIN32) *encoding = 28604; #elif defined(LINUX) *encoding = "ISO-8859-14"; #else *encoding = "ISO8859-14"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-15") == 0) { #if defined(WIN32) *encoding = 28605; #elif defined(LINUX) *encoding = "ISO-8859-15"; #else *encoding = "ISO8859-15"; #endif } else if (strIgnoreCaseCmp(encodingMB, "ISO-8859-16") == 0) { #if defined(WIN32) *encoding = 28606; #elif defined(LINUX) *encoding = "ISO-8859-16"; #else *encoding = "ISO8859-16"; #endif } else if (strIgnoreCaseCmp(encodingMB, "CP1250") == 0) { #if defined(WIN32) *encoding = 1250; #else *encoding = "CP1250"; #endif } else if (strIgnoreCaseCmp(encodingMB, "CP1251") == 0) { #if defined(WIN32) *encoding = 1251; #else *encoding = "CP1251"; #endif } else if (strIgnoreCaseCmp(encodingMB, "KOI8-R") == 0) { #if defined(WIN32) *encoding = 20866; #else *encoding = "KOI8-R"; #endif } else if (strIgnoreCaseCmp(encodingMB, "KOI8-U") == 0) { #if defined(WIN32) *encoding = 21866; #else *encoding = "KOI8-U"; #endif } else if (strIgnoreCaseCmp(encodingMB, "DEFAULT") == 0) { #ifdef WIN32 *encoding = GetACP(); #else *encoding = nl_langinfo(CODESET); #ifdef MACOSX if (strlen(*encoding) == 0) { *encoding = "UTF-8"; } #endif #endif } else { return TRUE; } return FALSE; } /** * Gets the error code for the last operation that failed. */ int wrapperGetLastError() { #ifdef WIN32 return WSAGetLastError(); #else return errno; #endif } /* * Corrects a path in place by replacing all '/' characters with '\' * on Windows platforms. Does nothing on NIX platforms. * * filename - Filename to be modified. Could be null. */ void wrapperCorrectWindowsPath(TCHAR *filename) { #ifdef WIN32 TCHAR *c; if (filename) { c = (TCHAR *)filename; while((c = _tcschr(c, TEXT('/'))) != NULL) { c[0] = TEXT('\\'); } } #endif } #ifdef FREEBSD /* * Tries to load libiconv and then fallback in FreeBSD. * Unfortunately we can not do any pretty logging here as iconv is * required for all of that to work. * * @return TRUE if there were any problems, FALSE otherwise. */ int loadIconvLibrary() { void *libHandle; const char *error; /* iconv library name present from FreeBSD 7 to 9 */ libHandle = dlopen("/usr/local/lib/libiconv.so", RTLD_NOW); /* Falling back to libbiconv library in FreeBSD 10 */ if (libHandle == NULL) { libHandle = dlopen("/usr/local/lib/libbiconv.so", RTLD_NOW); } /* Falling back to libkiconv.4 in FreeBSD 10 */ if (libHandle == NULL) { libHandle = dlopen("/lib/libkiconv.so.4", RTLD_NOW); } /* No library found, we cannot continue as we need iconv support */ if (!libHandle) { /* The string that dlerror is in a static buffer and should not be freed. It must be immediately used or copied. */ error = dlerror(); printf("Failed to locate the iconv library: %s\n", (error ? error : "")); printf("Unable to continue.\n"); return TRUE; } /* Look up the required functions. */ *(void **)(&wrapper_iconv_open) = dlsym(libHandle, "iconv_open"); if (!wrapper_iconv_open) { /* The string that dlerror is in a static buffer and should not be freed. It must be immediately used or copied. */ error = dlerror(); printf("Failed to locate the %s function from the iconv library: %s\n", "iconv_open", (error ? error : "")); printf("Unable to continue.\n"); return TRUE; } *(void **)(&wrapper_iconv) = dlsym(libHandle, "iconv"); if (!wrapper_iconv) { /* The string that dlerror is in a static buffer and should not be freed. It must be immediately used or copied. */ error = dlerror(); printf("Failed to locate the %s function from the iconv library: %s\n", "iconv", (error ? error : "")); printf("Unable to continue.\n"); return TRUE; } *(void **)(&wrapper_iconv_close) = dlsym(libHandle,"iconv_close"); if (!wrapper_iconv_close) { /* The string that dlerror is in a static buffer and should not be freed. It must be immediately used or copied. */ error = dlerror(); printf("Failed to locate the %s function from the iconv library: %s\n", "iconv_close", (error ? error : "")); printf("Unable to continue.\n"); return TRUE; } return FALSE; } #endif #ifdef DEBUG_MALLOC /* There can't be any more malloc calls after the malloc2 function in this file. */ #undef malloc void *malloc2(size_t size, const char *file, int line, const char *func, const char *sizeVar) { void *ptr; #ifdef WIN32 wprintf(L"%S:%d:%S malloc(%S) -> malloc(%d)", file, line, func, sizeVar, size); #else wprintf(L"%s:%d:%s malloc(%s) -> malloc(%d)", file, line, func, sizeVar, size); #endif ptr = malloc(size); wprintf(L" -> %p\n", ptr); return ptr; } #endif wrapper_3.5.26_src/src/c/wrapper_i18n.h100644 0 0 37740 12440202301 15067 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #ifndef _LOCALIZE #define _LOCALIZE #include #ifndef WIN32 #define MBSTOWCS_QUERY_LENGTH 0 #ifdef UNICODE #include #ifdef _sntprintf #undef _sntprintf #endif #include #include #include #include #include #include #include #include #include #define __max(x,y) (((x) > (y)) ? (x) : (y)) #define __min(x,y) (((x) < (y)) ? (x) : (y)) #if defined(SOLARIS) || defined(HPUX) #define WRAPPER_USE_PUTENV #endif #ifdef FREEBSD #include #endif #if defined(MACOSX) || defined(HPUX) || defined(FREEBSD) || defined(SOLARIS) #ifndef wcscasecmp extern int wcscasecmp(const wchar_t* s1, const wchar_t* s2); #define ECSCASECMP #endif #endif #define TEXT(x) L##x typedef wchar_t TCHAR; typedef wchar_t _TUCHAR; extern int _tprintf(const wchar_t *fmt,...) ; extern int multiByteToWideChar(const char *multiByteChars, const char *multiByteEncoding, char *interumEncoding, wchar_t **outputBuffer, int localizeErrorMessage); #define _taccess _waccess #define _tstoi64 _wtoi64 #define _ttoi64 _wtoi64 #define cgetts _cgetws extern int _tchdir(const TCHAR *path); extern int _texecvp(TCHAR* arg, TCHAR **cmd); extern int _tmkfifo(TCHAR* arg, mode_t mode); #define _tchmod _wchmod #define _tcprintf _cwprintf #define _cputts _cputws #define _tcreat _wcreat #define _tcscanf _cwscanf #define _tctime64 _wctime64 #define _texecl _wexecl #define _texecle _wexecle #define _texeclp _wexeclp #define _texeclpe _wexeclpe #define _texecv _wexecv extern int _texecve(TCHAR* arg, TCHAR **cmd, TCHAR** env); #define _texecvpe _wexecvpe #define _tfdopen _wfdopen #define _fgettchar _fgetwchar #define _tfindfirst _wfindfirst #define _tfindnext64 _wfindnext64 #define _tfindnext _wfindnext #define _tfindnexti64 _wfindnexti64 #define _fputtchar _fputwchar #define _tfsopen _wfsopen #define _tfullpath _wfullpath #define _gettch _getwch #define _gettche _getwche extern TCHAR* _tgetcwd(TCHAR *buf, size_t size); #define _tgetdcwd _wgetdcwd #define _ltot _ltow #define _tmakepath _wmakepath #define _tmkdir _wmkdir #define _tmktemp _wmktemp extern int _topen(const TCHAR *path, int oflag, mode_t mode); #define _tpopen _wpopen #define _puttch _putwch #if defined(WRAPPER_USE_PUTENV) extern int _tputenv(const TCHAR *string); #else extern int _tsetenv(const TCHAR *name, const TCHAR *value, int overwrite); extern void _tunsetenv(const TCHAR *name); #endif #define _trmdir _wrmdir #define _sctprintf _scwprintf #define _tsearchenv _wsearchenv #define _sntscanf _snwscanf #define _tsopen _wsopen #define _tspawnl _wspawnl #define _tspawnle _wspawnle #define _tspawnlp _wspawnlp #define _tspawnlpe _wspawnlpe #define _tspawnv _wspawnv #define _tspawnve _wspawnve #define _tspawnvp _wspawnvp #define _tspawnvpe _wspawnvpe #define _tsplitpath _wsplitpath #define _tstat64 _wstat64 extern int _tstat(const wchar_t* filename, struct stat *buf); #define _tstati64 _wstati64 #define _tstrdate _wstrdate #define _tcsdec _wcsdec #define _tcsdup _wcsdup #define _tcsicmp wcscasecmp /* Intentionally do not allow use of _trealpath because it does not specify a buffer length. * #define _trealpath * Define our own _trealpathN below. */ extern wchar_t* _trealpathN(const wchar_t* fileName, wchar_t *resolvedName, size_t resolvedNameSize); #define _tcsicoll _wcsicoll #define _tcsinc _wcsinc #define _tcslwr _wcslwr #define _tcsnbcnt _wcsncnt #define _tcsnccnt _wcsncnt #define _tcsnccnt _wcsncnt #define _tcsnccoll _wcsncoll #define _tcsnextc _wcsnextc #define _tcsncicmp _wcsnicmp #define _tcsnicmp _wcsnicmp #define _tcsncicoll _wcsnicoll #define _tcsnicoll _wcsnicoll #define _tcsninc _wcsninc #define _tcsncset _wcsnset #define _tcsnset _wcsnset #define _tcsrev _wcsrev #define _tcsset _wcsset #define _tcsspnp _wcsspnp #define _tstrtime wcsftime #define _tcstoi64 _wcstoi64 #define _tcstoui64 _wcstoui64 #define _tcsupr _wcsupr #define _ttempnam _wtempnam #define _ui64tot _ui64tow #define _ultot _ultow #define _ungettch _ungetwch extern int _tunlink(const wchar_t* address); #define _tutime64 _wutime64 #define _tutime _wutime #define _vsctprintf _vscwprintf #if defined(HPUX) extern int _vsntprintf(wchar_t *ws, size_t n, const wchar_t *format, va_list arg); #else #define _vsntprintf vswprintf #endif #define _tasctime _wasctime #define _tstof _wtof #define _tstoi _wtoi #define _ttoi(x) wcstol(x, NULL, 10) #define _tstol _wtol #define _ttol _wtol #define _tctime _wctime #define _fgettc fgetwc #define _fgetts fgetws extern FILE * _tfopen(const wchar_t* file, const wchar_t* mode) ; #define _fputtc fputwc #define _fputts fputws #define _tfreopen _wfreopen #define _ftscanf fwscanf #define _gettc getwc #define _gettchar getwchar /** * This Wrapper function internally does a malloc to generate the * Wide-char version of the return string. This must be freed by the caller. * Only needed inside the following: * #if !defined(WIN32) && defined(UNICODE) * #endif */ extern TCHAR * _tgetenv ( const TCHAR * name ); #define _getts getws #define _istalnum iswalnum #define _istalpha iswalpha #define _istascii iswascii #define _istcntrl iswcntrl #define _istdigit iswdigit #define _istgraph iswgraph #define _istleadbyte isleadbyte #define _istlower iswlower #define _istprint iswprint #define _istpunct iswpunct #define _istspace iswspace #define _istupper iswupper #define _istxdigit iswxdigit #define _tmain wmain #define _tperror _wperror /*_tprintf wprintf*/ #define _puttc putwc #define _puttchar putwchar #define _putts _putws extern int _tremove(const TCHAR *path); extern int _trename(const TCHAR *path, const TCHAR *to); extern void _topenlog(const TCHAR *ident, int logopt, int facility); extern void _tsyslog(int priority, const TCHAR *message); #define _tscanf wscanf extern TCHAR *_tsetlocale(int category, const TCHAR *locale) ; extern int _sntprintf(TCHAR *str, size_t size, const TCHAR *format, ...); #define _stprintf _sntprintf extern int _ftprintf(FILE *stream, const wchar_t *format, ...); #define _stscanf swscanf #define _tcscat wcscat #define _tcschr wcschr #define _tcscmp wcscmp #define _tcscoll wcscoll #define _tcscpy wcscpy #define _tcscspn wcscspn #define _tcserror _wcserror #define _tcsftime wcsftime #define _tcsclen wcslen #define _tcslen wcslen #define _tcsncat wcsncat #define _tcsnccat wcsncat #define _tcsnccmp wcsncmp #define _tcsncmp wcsncmp #define _tcsnccpy wcsncpy #define _tcsncpy wcsncpy #define _tcspbrk wcspbrk #define _tcsrchr wcsrchr #define _tcsspn wcsspn #define _tcsstr wcsstr #define _tcstod wcstod #define _tcstok wcstok #define _tcstol wcstol #define _tcstoul wcstoul #define _tcsxfrm wcsxfrm #define _tsystem _wsystem #define _ttmpnam _wtmpnam #define _totlower towlower #define _totupper towupper #define _ungettc ungetwc #define _vftprintf vfwprintf #define _vtprintf vwprintf #define _vstprintf vswprintf extern size_t _treadlink(TCHAR* exe, TCHAR* fullpath, size_t size); extern long _tpathconf(const TCHAR *path, int name); #else /* ASCII */ #define TEXT(x) x typedef char TCHAR; typedef unsigned char _TUCHAR; #define _tpathconf pathconf #define _taccess _access #define _treadlink readlink #define _tstoi64 _atoi64 #define _ttoi64 _atoi64 #define cgetts _cgets #define _tchdir chdir #define _tchmod chmod #define _tcprintf _cprintf #define _cputts _cputs #define _tcreat _creat #define _tcscanf _cscanf #define _tctime64 _ctime64 #define _tmkfifo mkfifo #define _texecl execl #define _texecle execle #define _texeclp execlp #define _texeclpe execlpe #define _texecv execv #define _texecve execve #define _texecvp execvp #define _texecvpe execvpe #define _tfdopen _fdopen #define _fgettchar _fgetchar #define _tfindfirst _findfirst #define _tfindnext64 _findnext64 #define _tfindnext _findnext #define _tfindnexti64 _findnexti64 #define _fputtchar _fputchar #define _tfsopen _fsopen #define _tfullpath _fullpath #define _gettch _getch #define _gettche _getche #define _tgetcwd getcwd #define _tgetdcwd getdcwd #define _ltot _ltoa #define _tmakepath _makepath #define _tmkdir _mkdir #define _tmktemp _mktemp #define _topen open #define _tpopen _popen #define _puttch _putch /*#define _tputenv putenv*/ #define _tsetenv setenv #define _tunsetenv unsetenv #define _trmdir _rmdir #define _sctprintf _scprintf #define _tsearchenv _searchenv #define _sntprintf _snprintf #define _sntscanf _snscanf #define _tsopen _sopen #define _tspawnl _spawnl #define _tspawnle _spawnle #define _tspawnlp _spawnlp #define _tspawnlpe _spawnlpe #define _tspawnv _spawnv #define _tspawnve _spawnve #define _tspawnvp _spawnvp #define _tspawnvpe _spawnvpe #define _tsplitpath _splitpath #define _tstat64 _stat64 #define _tstat stat #define _tstati64 _stati64 #define _tstrdate _strdate #define _tcsdec _strdec #define _tcsdup _strdup #define _tcsicmp strcasecmp #define _tcsicoll _stricoll #define _tcsinc _strinc /* Intentionally do not allow use of _trealpath because it does not specify a buffer length. * #define _trealpath realpath * Define our own _trealpathN below. */ #define _trealpathN(fileName, resolvedName, resolvedNameSize) realpath(fileName, resolvedName) #define _tcslwr _strlwr #define _tcsnbcnt _strncnt #define _tcsnccnt _strncnt #define _tcsnccnt _strncnt #define _tcsnccoll _strncoll #define _tcsnextc _strnextc #define _tcsncicmp _strnicmp #define _tcsnicmp _strnicmp #define _tcsncicoll _strnicoll #define _tcsnicoll _strnicoll #define _tcsninc _strninc #define _tcsncset _strnset #define _tcsnset _strnset #define _tcsrev _strrev #define _tcsset _strset #define _tcsspnp _strspnp #define _tstrtime strftime #define _tcstoi64 _strtoi64 #define _tcstoui64 _strtoui64 #define _tcsupr _strupr #define _ttempnam _tempnam #define _ui64tot _ui64toa #define _ultot _ultoa #define _ungettch _ungetch #define _tunlink unlink #define _tutime64 _utime64 #define _tutime _utime #define _vsctprintf _vscprintf #define _vsntprintf vsnprintf #define _tasctime asctime #define _tstof atof #define _tstoi atoi #define _ttoi atoi #define _tstol atol #define _ttol atol #define _tctime ctime #define _fgettc fgetc #define _fgetts fgets #define _tfopen fopen #define _ftprintf fprintf #define _fputtc fputc #define _fputts fputs #define _tfreopen freopen #define _ftscanf fscanf #define _gettc getc #define _gettchar getchar #define _tgetenv getenv #define _getts gets #define _istalnum isalnum #define _istalpha isalpha #define _istascii isascii #define _istcntrl iscntrl #define _istdigit isdigit #define _istgraph isgraph #define _istlead islead #define _istleadbyte isleadbyte #define _istlegal islegal #define _istlower islower #define _istprint isprint #define _istpunct ispunct #define _istspace isspace #define _istupper isupper #define _istxdigit isxdigit #define _tmain main #define _tperror perror #define _tprintf printf #define _puttc putc #define _puttchar putchar #define _putts puts #define _tremove remove #define _trename rename #define _tscanf scanf #define _tsetlocale setlocale #define _sntprintf snprintf #define _stscanf sscanf #define _tcscat strcat #define _tcschr strchr #define _tcscmp strcmp #define _tcscoll strcoll #define _tcscpy strcpy #define _tcscspn strcspn #define _tcserror strerror #define _tcsftime strftime #define _tcsclen strlen #define _tcslen strlen #define _tcsncat strncat #define _tcsnccat strncat #define _tcsnccmp strncmp #define _tcsncmp strncmp #define _tcsnccpy strncpy #define _tcsncpy strncpy #define _tcspbrk strpbrk #define _tcsrchr strrchr #define _tcsspn strspn #define _tcsstr strstr #define _tcstod strtod #define _tcstok strtok #define _tcstol strtol #define _tcstoul strtoul #define _tcsxfrm strxfrm #define _tsystem system #define _ttmpnam tmpnam #define _totlower tolower #define _totupper toupper #define _ungettc ungetc #define _vftprintf vfprintf #define _vtprintf vprintf #define _vstprintf vsprintf #define _topenlog openlog #define _tsyslog syslog #endif #else /* WIN32 */ #include #include #include extern int multiByteToWideChar(const char *multiByteChars, int encoding, TCHAR **outputBufferW, int localizeErrorMessage); #endif #ifdef FREEBSD /* * Tries to load libiconv and then fallback in FreeBSD. * Unfortunately we can not do any pretty logging here as iconv is * required for all of that to work. * * @return TRUE if there were any problems, FALSE otherwise. */ extern int loadIconvLibrary(); #endif /** * Define a cross platform way to compare strings while ignoring case. */ #ifdef WIN32 #define strIgnoreCaseCmp _stricmp #else #define strIgnoreCaseCmp strcasecmp #endif /** * Function to get the system encoding name/number for the encoding * of the conf file * * @para String holding the encoding from the conf file * * @return TRUE if not found, FALSE otherwise * */ #ifdef WIN32 extern int getEncodingByName(char* encodingMB, int *encoding); #else extern int getEncodingByName(char* encodingMB, char** encoding); #endif /** * Gets the error code for the last operation that failed. */ extern int wrapperGetLastError(); /* * Corrects a path in place by replacing all '/' characters with '\' * on Windows platforms. Does nothing on NIX platforms. * * filename - Filename to be modified. Could be null. */ extern void wrapperCorrectWindowsPath(TCHAR *filename); #endif /* Helper defines used to help trace where certain calls are being made. */ /*#define DEBUG_MBSTOWCS*/ #ifdef DEBUG_MBSTOWCS #ifdef WIN32 #define mbstowcs(x,y,z) mbstowcs(x,y,z); wprintf(L"%S:%d:%S mbstowcs(%S, %S, %S) -> mbstowcs(%p, \"%S\", %d)\n", __FILE__, __LINE__, __FUNCTION__, #x, #y, #z, (void *)x, y, (int)z) #else #define mbstowcs(x,y,z) mbstowcs(x,y,z); wprintf(L"%s:%d:%s mbstowcs(%s, %s, %s) -> mbstowcs(%p, \"%s\", %d)\n", __FILE__, __LINE__, __FUNCTION__, #x, #y, #z, (void *)x, y, (int)z) #endif #endif /*#define DEBUG_MALLOC*/ #ifdef DEBUG_MALLOC extern void *malloc2(size_t size, const char *file, int line, const char *func, const char *sizeVar); #define malloc(x) malloc2(x, __FILE__, __LINE__, __FUNCTION__, #x) #ifdef WIN32 #define free(x) wprintf(L"%S:%d:%S free(%S) -> free(%p)\n", __FILE__, __LINE__, __FUNCTION__, #x, (void *)x); free(x) #else #define free(x) wprintf(L"%s:%d:%s free(%s) -> free(%p)\n", __FILE__, __LINE__, __FUNCTION__, #x, (void *)x); free(x) #endif #endif wrapper_3.5.26_src/src/c/wrapper_unix.c100644 0 0 220115 12440202301 15274 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * Author: * Leif Mortenson * Ryan Shaw */ #ifndef WIN32 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wrapper_i18n.h" #include "wrapper.h" #include "wrapperinfo.h" #include "property.h" #include "logger.h" #include "wrapper_file.h" #include #include #if defined(IRIX) #define PATH_MAX FILENAME_MAX #endif #ifndef USE_USLEEP #include #endif #ifndef getsid /* getpid links ok on Linux, but is not defined correctly. */ pid_t getsid(pid_t pid); #endif #define max(x,y) (((x) > (y)) ? (x) : (y)) #define min(x,y) (((x) < (y)) ? (x) : (y)) /* Define a global pipe descriptor so that we don't have to keep allocating * a new pipe each time a JVM is launched. */ int pipedes[2] = {-1, -1}; #define PIPE_READ_END 0 #define PIPE_WRITE_END 1 /** * maximum length for a user name should be 8, * but according to 'man useradd' it may be 32 */ #define MAX_USER_NAME_LENGTH 32 TCHAR wrapperClasspathSeparator = TEXT(':'); int javaIOThreadSet = FALSE; pthread_t javaIOThreadId; int javaIOThreadStarted = FALSE; int stopJavaIOThread = FALSE; int javaIOThreadStopped = FALSE; int timerThreadSet = FALSE; pthread_t timerThreadId; int timerThreadStarted = FALSE; int stopTimerThread = FALSE; int timerThreadStopped = FALSE; TICKS timerTicks = WRAPPER_TICK_INITIAL; /****************************************************************************** * Platform specific methods *****************************************************************************/ /** * exits the application after running shutdown code. */ void appExit(int exitCode, int argc, TCHAR** argv) { int i; /* Remove pid file. It may no longer exist. */ if (wrapperData->pidFilename) { _tunlink(wrapperData->pidFilename); } /* Remove lock file. It may no longer exist. */ if (wrapperData->lockFilename) { _tunlink(wrapperData->lockFilename); } /* Remove status file. It may no longer exist. */ if (wrapperData->statusFilename) { _tunlink(wrapperData->statusFilename); } /* Remove java status file if it was registered and created by this process. */ if (wrapperData->javaStatusFilename) { _tunlink(wrapperData->javaStatusFilename); } /* Remove java id file if it was registered and created by this process. */ if (wrapperData->javaIdFilename) { _tunlink(wrapperData->javaIdFilename); } /* Remove anchor file. It may no longer exist. */ if (wrapperData->anchorFilename) { _tunlink(wrapperData->anchorFilename); } /* Common wrapper cleanup code. */ wrapperDispose(); #if defined(UNICODE) for (i = 0; i < argc; i++) { if (argv[i]) { free(argv[i]); } } if (argv) { free(argv); } #endif exit(exitCode); } /** * Writes a PID to disk. * * filename: File to write to. * pid: pid to write in the file. * strict: If true then an error will be reported and the call will fail if the * file already exists. * * return 1 if there was an error, 0 if Ok. */ int writePidFile(const TCHAR *filename, DWORD pid, int newUmask, int strict) { FILE *pid_fp = NULL; int old_umask; if (strict && wrapperFileExists(filename)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("%d pid file, %s, already exists."), pid, filename); return 1; } old_umask = umask(newUmask); pid_fp = _tfopen(filename, TEXT("w")); umask(old_umask); if (pid_fp != NULL) { _ftprintf(pid_fp, TEXT("%d\n"), (int)pid); fclose(pid_fp); } else { return 1; } return 0; } /** * Send a signal to the JVM process asking it to dump its JVM state. */ void wrapperRequestDumpJVMState() { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Dumping JVM state.")); if (kill(wrapperData->javaPID, SIGQUIT) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Could not dump JVM state: %s"), getLastErrorText()); } } /** * Called when a signal is processed. This is actually called from within the main event loop * and NOT the signal handler. So it is safe to use the normal logging functions. * * @param sigNum Signal that was fired. * @param sigName Name of the signal for logging. * @param mode Action that should be taken. */ void takeSignalAction(int sigNum, const TCHAR *sigName, int mode) { if (wrapperData->ignoreSignals & WRAPPER_IGNORE_SIGNALS_WRAPPER) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped, but ignored."), sigName); } else { switch (mode) { case WRAPPER_SIGNAL_MODE_RESTART: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. %s"), sigName, wrapperGetRestartProcessMessage()); wrapperRestartProcess(); break; case WRAPPER_SIGNAL_MODE_SHUTDOWN: if (wrapperData->exitRequested || wrapperData->restartRequested || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) || (wrapperData->jState == WRAPPER_JSTATE_STOP) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED) || (wrapperData->jState == WRAPPER_JSTATE_KILLING) || (wrapperData->jState == WRAPPER_JSTATE_KILL) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH)) { /* Signaled while we were already shutting down. */ if (wrapperData->isForcedShutdownDisabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Already shutting down."), sigName); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Forcing immediate shutdown."), sigName); /* Disable the thread dump on exit feature if it is set because it * should not be displayed when the user requested the immediate exit. */ wrapperData->requestThreadDumpOnFailedJVMExit = FALSE; wrapperKillProcess(); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Shutting down."), sigName); /* Always force the shutdown as this is an external event. */ wrapperStopProcess(0, TRUE); } /* Don't actually kill the process here. Let the application shut itself down */ /* To make sure that the JVM will not be restarted for any reason, * start the Wrapper shutdown process as well. */ if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { /* Already stopping. */ } else { wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } break; case WRAPPER_SIGNAL_MODE_FORWARD: if (wrapperData->javaPID > 0) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s trapped. Forwarding to JVM process."), sigName); } if (kill(wrapperData->javaPID, sigNum)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to forward %s signal to JVM process. %s"), sigName, getLastErrorText()); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Unable to forward signal to JVM because it is not running."), sigName); } break; default: /* WRAPPER_SIGNAL_MODE_IGNORE */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped, but ignored."), sigName); break; } } } /** * This function goes through and checks flags for each of several signals to see if they * have been fired since the last time this function was called. This is the only thread * which will ever clear these flags, but they can be set by other threads within the * signal handlers at ANY time. So only check the value of each flag once and reset them * immediately to decrease the chance of missing duplicate signals. */ void wrapperMaintainSignals() { /* SIGINT */ if (wrapperData->signalInterruptTrapped) { wrapperData->signalInterruptTrapped = FALSE; takeSignalAction(SIGINT, TEXT("INT"), WRAPPER_SIGNAL_MODE_SHUTDOWN); } /* SIGQUIT */ if (wrapperData->signalQuitTrapped) { wrapperData->signalQuitTrapped = FALSE; wrapperRequestDumpJVMState(); } /* SIGCHLD */ if (wrapperData->signalChildTrapped) { wrapperData->signalChildTrapped = FALSE; wrapperGetProcessStatus(wrapperGetTicks(), TRUE); } /* SIGTERM */ if (wrapperData->signalTermTrapped) { wrapperData->signalTermTrapped = FALSE; takeSignalAction(SIGTERM, TEXT("TERM"), WRAPPER_SIGNAL_MODE_SHUTDOWN); } /* SIGHUP */ if (wrapperData->signalHUPTrapped) { wrapperData->signalHUPTrapped = FALSE; takeSignalAction(SIGHUP, TEXT("HUP"), wrapperData->signalHUPMode); } /* SIGUSR1 */ if (wrapperData->signalUSR1Trapped) { wrapperData->signalUSR1Trapped = FALSE; takeSignalAction(SIGUSR1, TEXT("USR1"), wrapperData->signalUSR1Mode); } #ifndef VALGRIND /* SIGUSR2 */ if (wrapperData->signalUSR2Trapped) { wrapperData->signalUSR2Trapped = FALSE; takeSignalAction(SIGUSR2, TEXT("USR2"), wrapperData->signalUSR2Mode); } #endif } /** * This is called from within signal handlers so NO MALLOCs are allowed here. */ const TCHAR* getSignalName(int signo) { switch (signo) { case SIGALRM: return TEXT("SIGALRM"); case SIGINT: return TEXT("SIGINT"); case SIGKILL: return TEXT("SIGKILL"); case SIGQUIT: return TEXT("SIGQUIT"); case SIGCHLD: return TEXT("SIGCHLD"); case SIGTERM: return TEXT("SIGTERM"); case SIGHUP: return TEXT("SIGHUP"); case SIGUSR1: return TEXT("SIGUSR1"); case SIGUSR2: return TEXT("SIGUSR2"); case SIGSEGV: return TEXT("SIGSEGV"); default: return TEXT("UNKNOWN"); } } /** * This is called from within signal handlers so NO MALLOCs are allowed here. */ const TCHAR* getSignalCodeDesc(int code) { switch (code) { #ifdef SI_USER case SI_USER: return TEXT("kill, sigsend or raise"); #endif #ifdef SI_KERNEL case SI_KERNEL: return TEXT("the kernel"); #endif case SI_QUEUE: return TEXT("sigqueue"); #ifdef SI_TIMER case SI_TIMER: return TEXT("timer expired"); #endif #ifdef SI_MESGQ case SI_MESGQ: return TEXT("mesq state changed"); #endif case SI_ASYNCIO: return TEXT("AIO completed"); #ifdef SI_SIGIO case SI_SIGIO: return TEXT("queued SIGIO"); #endif default: return TEXT("unknown"); } } /** * Describe a signal. This is called from within signal handlers so NO MALLOCs are allowed here. */ void descSignal(siginfo_t *sigInfo) { #ifdef SI_USER struct passwd *pw; #ifdef UNICODE size_t req; #endif TCHAR uName[MAX_USER_NAME_LENGTH + 1]; #endif /* Not supported on all platforms */ if (sigInfo == NULL) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Signal trapped. No details available.")); return; } if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Signal trapped. Details:")); log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, #if defined(UNICODE) TEXT(" signal number=%d (%S), source=\"%S\""), #else TEXT(" signal number=%d (%s), source=\"%s\""), #endif sigInfo->si_signo, getSignalName(sigInfo->si_signo), getSignalCodeDesc(sigInfo->si_code)); if (sigInfo->si_errno != 0) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, #if defined(UNICODE) TEXT(" signal err=%d, \"%S\""), #else TEXT(" signal err=%d, \"%s\""), #endif sigInfo->si_errno, strerror(sigInfo->si_errno)); } #ifdef SI_USER if (sigInfo->si_code == SI_USER) { pw = getpwuid(sigInfo->si_uid); if (pw == NULL) { _sntprintf(uName, MAX_USER_NAME_LENGTH + 1, TEXT("")); } else { #ifndef UNICODE _sntprintf(uName, MAX_USER_NAME_LENGTH + 1, TEXT("%s"), pw->pw_name); #else req = mbstowcs(NULL, pw->pw_name, MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { return; } if (req > MAX_USER_NAME_LENGTH) { req = MAX_USER_NAME_LENGTH; } mbstowcs(uName, pw->pw_name, req + 1); uName[req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ #endif } /* It appears that the getsid function was added in version 1.3.44 of the linux kernel. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, #ifdef UNICODE TEXT(" signal generated by PID: %d (Session PID: %d), UID: %d (%S)"), #else TEXT(" signal generated by PID: %d (Session PID: %d), UID: %d (%s)"), #endif sigInfo->si_pid, getsid(sigInfo->si_pid), sigInfo->si_uid, uName); } #endif } } /** * Handle alarm signals. We are getting them on solaris when running with * the tick timer. Not yet sure where they are coming from. */ void sigActionAlarm(int sigNum, siginfo_t *sigInfo, void *na) { pthread_t threadId; /* On UNIX the calling thread is the actual thread being interrupted * so it has already been registered with logRegisterThread. */ descSignal(sigInfo); threadId = pthread_self(); if (wrapperData->isDebugging) { if (timerThreadSet && pthread_equal(threadId, timerThreadId)) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Timer thread received an Alarm signal. Ignoring.")); } else { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Received an Alarm signal. Ignoring.")); } } } /** * Handle interrupt signals (i.e. Crtl-C). */ void sigActionInterrupt(int sigNum, siginfo_t *sigInfo, void *na) { /* On UNIX the calling thread is the actual thread being interrupted * so it has already been registered with logRegisterThread. */ descSignal(sigInfo); wrapperData->signalInterruptTrapped = TRUE; } /** * Handle quit signals (i.e. Crtl-\). */ void sigActionQuit(int sigNum, siginfo_t *sigInfo, void *na) { pthread_t threadId; /* On UNIX the calling thread is the actual thread being interrupted * so it has already been registered with logRegisterThread. */ descSignal(sigInfo); threadId = pthread_self(); if (timerThreadSet && pthread_equal(threadId, timerThreadId)) { if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Timer thread received an Quit signal. Ignoring.")); } } else { wrapperData->signalQuitTrapped = TRUE; } } /** * Handle termination signals (i.e. machine is shutting down). */ void sigActionChildDeath(int sigNum, siginfo_t *sigInfo, void *na) { pthread_t threadId; /* On UNIX, when a Child process changes state, a SIGCHLD signal is sent to the parent. * The parent should do a wait to make sure the child is cleaned up and doesn't become * a zombie process. */ threadId = pthread_self(); if (timerThreadSet && pthread_equal(threadId, timerThreadId)) { if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Timer thread received a SigChild signal. Ignoring.")); } } else { descSignal(sigInfo); if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Received SIGCHLD, checking JVM process status.")); } /* This is set whenever any child signals that it has exited. * Inside the code we go on to check to make sure that we only test for the JVM */ wrapperData->signalChildTrapped = TRUE; } } /** * Handle termination signals (i.e. machine is shutting down). */ void sigActionTermination(int sigNum, siginfo_t *sigInfo, void *na) { /* On UNIX the calling thread is the actual thread being interrupted * so it has already been registered with logRegisterThread. */ descSignal(sigInfo); wrapperData->signalTermTrapped = TRUE; } /** * Handle hangup signals. */ void sigActionHangup(int sigNum, siginfo_t *sigInfo, void *na) { /* On UNIX the calling thread is the actual thread being interrupted * so it has already been registered with logRegisterThread. */ descSignal(sigInfo); wrapperData->signalHUPTrapped = TRUE; } /** * Handle USR1 signals. */ void sigActionUSR1(int sigNum, siginfo_t *sigInfo, void *na) { /* On UNIX the calling thread is the actual thread being interrupted * so it has already been registered with logRegisterThread. */ descSignal(sigInfo); wrapperData->signalUSR1Trapped = TRUE; } /** * Handle USR2 signals. */ void sigActionUSR2(int sigNum, siginfo_t *sigInfo, void *na) { /* On UNIX the calling thread is the actual thread being interrupted * so it has already been registered with logRegisterThread. */ descSignal(sigInfo); wrapperData->signalUSR2Trapped = TRUE; } /** * Registers a single signal handler. */ int registerSigAction(int sigNum, void (*sigAction)(int, siginfo_t *, void *)) { struct sigaction newAct; newAct.sa_sigaction = sigAction; sigemptyset(&newAct.sa_mask); newAct.sa_flags = SA_SIGINFO; if (sigaction(sigNum, &newAct, NULL)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to register signal handler for signal %d. %s"), sigNum, getLastErrorText()); return 1; } return 0; } /** * The main entry point for the javaio thread which is started by * initializeJavaIO(). Once started, this thread will run for the * life of the process. * * This thread will only be started if we are configured to use a * dedicated thread to read JVM output. */ void *javaIORunner(void *arg) { sigset_t signal_mask; int nextSleep; #ifndef VALGRIND int rc; #endif javaIOThreadStarted = TRUE; /* Immediately register this thread with the logger. */ logRegisterThread(WRAPPER_THREAD_JAVAIO); /* mask signals so the javaIO doesn't get any of these. */ sigemptyset(&signal_mask); sigaddset(&signal_mask, SIGTERM); sigaddset(&signal_mask, SIGINT); sigaddset(&signal_mask, SIGQUIT); sigaddset(&signal_mask, SIGALRM); sigaddset(&signal_mask, SIGHUP); sigaddset(&signal_mask, SIGUSR1); #ifndef VALGRIND sigaddset(&signal_mask, SIGUSR2); rc = pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); if (rc != 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Could not mask signals for javaIO thread.")); } #endif if (wrapperData->isJavaIOOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JavaIO thread started.")); } nextSleep = TRUE; /* Loop until we are shutting down, but continue as long as there is more output from the JVM. */ while ((!stopJavaIOThread) || (!nextSleep)) { if (nextSleep) { /* Sleep as little as possible. */ wrapperSleep(1); } nextSleep = TRUE; if (wrapperData->pauseThreadJavaIO) { wrapperPauseThread(wrapperData->pauseThreadJavaIO, TEXT("javaio")); wrapperData->pauseThreadJavaIO = 0; } if (wrapperReadChildOutput(0)) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Pause reading child process output to share cycles.")); } nextSleep = FALSE; } } javaIOThreadStopped = TRUE; if (wrapperData->isJavaIOOutputEnabled) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JavaIO thread stopped.")); } return NULL; } /** * Creates a process whose job is to loop and simply increment a ticks * counter. The tick counter can then be used as a clock as an alternative * to using the system clock. */ int initializeJavaIO() { int res; if (wrapperData->isJavaIOOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Launching JavaIO thread.")); } res = pthread_create(&javaIOThreadId, NULL, /* No attributes. */ javaIORunner, NULL); /* No parameters need to be passed to the thread. */ if (res) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to create a javaIO thread: %d, %s"), res, getLastErrorText()); javaIOThreadSet = TRUE; return 1; } else { if (pthread_detach(javaIOThreadId)) { javaIOThreadSet = TRUE; return 1; } javaIOThreadSet = FALSE; return 0; } } void disposeJavaIO() { stopJavaIOThread = TRUE; /* Wait until the javaIO thread is actually stopped to avoid timing problems. */ if (javaIOThreadStarted) { while (!javaIOThreadStopped) { #ifdef _DEBUG wprintf(TEXT("Waiting for javaIO thread to stop.\n")); #endif wrapperSleep(100); } pthread_cancel(javaIOThreadId); } } /** * The main entry point for the timer thread which is started by * initializeTimer(). Once started, this thread will run for the * life of the process. * * This thread will only be started if we are configured NOT to * use the system time as a base for the tick counter. */ void *timerRunner(void *arg) { TICKS sysTicks; TICKS lastTickOffset = 0; TICKS tickOffset; TICKS nowTicks; int offsetDiff; int first = TRUE; sigset_t signal_mask; #ifndef VALGRIND int rc; #endif timerThreadStarted = TRUE; /* Immediately register this thread with the logger. */ logRegisterThread(WRAPPER_THREAD_TIMER); /* mask signals so the timer doesn't get any of these. */ sigemptyset(&signal_mask); sigaddset(&signal_mask, SIGTERM); sigaddset(&signal_mask, SIGINT); sigaddset(&signal_mask, SIGQUIT); sigaddset(&signal_mask, SIGALRM); sigaddset(&signal_mask, SIGHUP); sigaddset(&signal_mask, SIGUSR1); #ifndef VALGRIND sigaddset(&signal_mask, SIGUSR2); rc = pthread_sigmask(SIG_BLOCK, &signal_mask, NULL); if (rc != 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Could not mask signals for timer thread.")); } #endif if (wrapperData->isTickOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Timer thread started.")); } while (!stopTimerThread) { wrapperSleep(WRAPPER_TICK_MS); if (wrapperData->pauseThreadTimer) { wrapperPauseThread(wrapperData->pauseThreadTimer, TEXT("timer")); wrapperData->pauseThreadTimer = 0; } /* Get the tick count based on the system time. */ sysTicks = wrapperGetSystemTicks(); /* Lock the tick mutex whenever the "timerTicks" variable is accessed. */ if (wrapperData->useTickMutex && wrapperLockTickMutex()) { timerThreadStopped = TRUE; return NULL; } /* Advance the timer tick count. */ nowTicks = timerTicks++; if (wrapperData->useTickMutex && wrapperReleaseTickMutex()) { timerThreadStopped = TRUE; return NULL; } /* Calculate the offset between the two tick counts. This will always work due to overflow. */ tickOffset = sysTicks - nowTicks; /* The number we really want is the difference between this tickOffset and the previous one. */ offsetDiff = wrapperGetTickAgeTicks(lastTickOffset, tickOffset); if (first) { first = FALSE; } else { if (offsetDiff > wrapperData->timerSlowThreshold) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("The timer fell behind the system clock by %ldms."), offsetDiff * WRAPPER_TICK_MS); } else if (offsetDiff < -1 * wrapperData->timerFastThreshold) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("The system clock fell behind the timer by %ldms."), -1 * offsetDiff * WRAPPER_TICK_MS); } if (wrapperData->isTickOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT( " Timer: ticks=0x%08x, system ticks=0x%08x, offset=0x%08x, offsetDiff=0x%08x"), nowTicks, sysTicks, tickOffset, offsetDiff); } } /* Store this tick offset for the next time through the loop. */ lastTickOffset = tickOffset; } timerThreadStopped = TRUE; if (wrapperData->isTickOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Timer thread stopped.")); } return NULL; } /** * Creates a process whose job is to loop and simply increment a ticks * counter. The tick counter can then be used as a clock as an alternative * to using the system clock. */ int initializeTimer() { int res; if (wrapperData->isTickOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Launching Timer thread.")); } res = pthread_create(&timerThreadId, NULL, /* No attributes. */ timerRunner, NULL); /* No parameters need to be passed to the thread. */ if (res) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to create a timer thread: %d, %s"), res, getLastErrorText()); timerThreadSet = TRUE; return 1; } else { if (pthread_detach(timerThreadId)) { timerThreadSet = TRUE; return 1; } timerThreadSet = FALSE; return 0; } } void disposeTimer() { stopTimerThread = TRUE; /* Wait until the timer thread is actually stopped to avoid timing problems. */ if (timerThreadStarted) { while (!timerThreadStopped) { #ifdef _DEBUG wprintf(TEXT("Waiting for timer thread to stop.\n")); #endif wrapperSleep(100); } pthread_cancel(timerThreadId); } } /** * Execute initialization code to get the wrapper set up. */ int wrapperInitializeRun() { int retval = 0; int res; /* Register any signal actions we are concerned with. */ if (registerSigAction(SIGALRM, sigActionAlarm) || registerSigAction(SIGINT, sigActionInterrupt) || registerSigAction(SIGQUIT, sigActionQuit) || registerSigAction(SIGCHLD, sigActionChildDeath) || registerSigAction(SIGTERM, sigActionTermination) || registerSigAction(SIGHUP, sigActionHangup) || registerSigAction(SIGUSR1, sigActionUSR1) #ifndef VALGRIND || registerSigAction(SIGUSR2, sigActionUSR2) #endif ) { retval = -1; } /* Attempt to set the console title if it exists and is accessable. * This works on all UNIX versions, but only Linux resets it * correctly when the wrapper process terminates. */ #if defined(LINUX) if (wrapperData->consoleTitle) { if (wrapperData->isConsole) { /* The console should be visible. */ _tprintf(TEXT("%c]0;%s%c"), TEXT('\033'), wrapperData->consoleTitle, TEXT('\007')); } } #endif if (wrapperData->useSystemTime) { /* We are going to be using system time so there is no reason to start up a timer thread. */ timerThreadSet = FALSE; /* Unable to set the timerThreadId to a null value on all platforms * timerThreadId = 0;*/ } else { /* Create and initialize a timer thread. */ if ((res = initializeTimer()) != 0) { return res; } } if (wrapperData->useJavaIOThread) { /* Create and initialize a javaIO thread. */ if ((res = initializeJavaIO()) != 0) { return res; } } else { javaIOThreadSet = FALSE; /* Unable to set the javaIOThreadId to a null value on all platforms * javaIOThreadId = 0;*/ } return retval; } /** * Cause the current thread to sleep for the specified number of milliseconds. * Sleeps over one second are not allowed. * * @param ms Number of milliseconds to wait for. * * @return TRUE if the was interrupted, FALSE otherwise. Neither is an error. */ int wrapperSleep(int ms) { /* We want to use nanosleep if it is available, but make it possible for the user to build a version that uses usleep if they want. usleep does not behave nicely with signals thrown while sleeping. This was the believed cause of a hang experienced on one Solaris system. */ #ifdef USE_USLEEP if (wrapperData->isSleepOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Sleep: usleep %dms"), ms); } usleep(ms * 1000); /* microseconds */ #else struct timespec ts; if (ms >= 1000) { ts.tv_sec = (ms * 1000000) / 1000000000; ts.tv_nsec = (ms * 1000000) % 1000000000; /* nanoseconds */ } else { ts.tv_sec = 0; ts.tv_nsec = ms * 1000000; /* nanoseconds */ } if (wrapperData->isSleepOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Sleep: nanosleep %dms"), ms); } if (nanosleep(&ts, NULL)) { if (errno == EINTR) { if (wrapperData->isSleepOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Sleep: nanosleep interrupted")); } return TRUE; } else if (errno == EAGAIN) { /* On 64-bit AIX this happens once on shutdown. */ if (wrapperData->isSleepOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Sleep: nanosleep unavailable")); } return TRUE; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("nanosleep(%dms) failed. %s"), ms, getLastErrorText()); } } #endif if (wrapperData->isSleepOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Sleep: awake")); } return FALSE; } /** * Detaches the Java process so the Wrapper will if effect forget about it. */ void wrapperDetachJava() { wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, 0, -1); /* Leave the stdout/stderr pipe in pipedes alone so we grab any remaining output. * They should have been redirected on the JVM side anyway. */ } /** * Build the java command line. * * @return TRUE if there were any problems. */ int wrapperBuildJavaCommand() { TCHAR **strings; int length, i; /* If this is not the first time through, then dispose the old command array */ if (wrapperData->jvmVersionCommand) { i = 0; while(wrapperData->jvmVersionCommand[i] != NULL) { free(wrapperData->jvmVersionCommand[i]); wrapperData->jvmVersionCommand[i] = NULL; i++; } free(wrapperData->jvmVersionCommand); wrapperData->jvmVersionCommand = NULL; } if (wrapperData->jvmCommand) { i = 0; while(wrapperData->jvmCommand[i] != NULL) { free(wrapperData->jvmCommand[i]); wrapperData->jvmCommand[i] = NULL; i++; } free(wrapperData->jvmCommand); wrapperData->jvmCommand = NULL; } /* First generate the classpath. */ if (wrapperData->classpath) { free(wrapperData->classpath); wrapperData->classpath = NULL; } if (wrapperBuildJavaClasspath(&wrapperData->classpath) < 0) { return TRUE; } /* Build the Java Command Strings */ strings = NULL; length = 0; if (wrapperBuildJavaCommandArray(&strings, &length, FALSE, wrapperData->classpath)) { return TRUE; } /* Allocate memory to hold array of version command strings. The array is itself NULL terminated */ wrapperData->jvmVersionCommand = malloc(sizeof(TCHAR *) * (2 + 1)); if (!wrapperData->jvmVersionCommand) { outOfMemory(TEXT("WBJC"), 1); return TRUE; } memset(wrapperData->jvmVersionCommand, 0, sizeof(TCHAR *) * (2 + 1)); /* Java Command */ wrapperData->jvmVersionCommand[0] = malloc(sizeof(TCHAR) * (_tcslen(strings[0]) + 1)); if (!wrapperData->jvmVersionCommand[0]) { outOfMemory(TEXT("WBJC"), 2); return TRUE; } _tcsncpy(wrapperData->jvmVersionCommand[0], strings[0], _tcslen(strings[0]) + 1); /* -version */ wrapperData->jvmVersionCommand[1] = malloc(sizeof(TCHAR) * (8 + 1)); if (!wrapperData->jvmVersionCommand[1]) { outOfMemory(TEXT("WBJC"), 3); return TRUE; } _tcsncpy(wrapperData->jvmVersionCommand[1], TEXT("-version"), 8 + 1); /* NULL */ wrapperData->jvmVersionCommand[2] = NULL; /* Allocate memory to hold array of command strings. The array is itself NULL terminated */ wrapperData->jvmCommand = malloc(sizeof(TCHAR *) * (length + 1)); if (!wrapperData->jvmCommand) { outOfMemory(TEXT("WBJC"), 1); return TRUE; } memset(wrapperData->jvmCommand, 0, sizeof(TCHAR *) * (length + 1)); /* number of arguments + 1 for a NULL pointer at the end */ for (i = 0; i <= length; i++) { if (i < length) { wrapperData->jvmCommand[i] = malloc(sizeof(TCHAR) * (_tcslen(strings[i]) + 1)); if (!wrapperData->jvmCommand[i]) { outOfMemory(TEXT("WBJC"), 2); return TRUE; } _tcsncpy(wrapperData->jvmCommand[i], strings[i], _tcslen(strings[i]) + 1); wrapperData->jvmCommand[i] = wrapperPostProcessCommandElement(wrapperData->jvmCommand[i]); } else { wrapperData->jvmCommand[i] = NULL; } } /* Free up the temporary command array */ wrapperFreeJavaCommandArray(strings, length); return FALSE; } /** * Calculate the total length of the environment assuming that they are separated by spaces. */ size_t wrapperCalculateEnvironmentLength() { /* The compiler won't let us reverence environ directly in the for loop on OSX because it is actually a function. */ char **environment = environ; size_t i; size_t len; size_t lenTotal; i = 0; lenTotal = 0; while (environment[i]) { /* All we need is the length so we don't actually have to convert them. */ len = mbstowcs(NULL, environment[i], MBSTOWCS_QUERY_LENGTH); if (len == (size_t)-1) { /* Invalid string. Skip. */ } else { /* Add length of variable + null + pointer to next element */ lenTotal += len + 1 + sizeof(char *); } i++; } /* Null termination of the list. */ lenTotal += sizeof(char *) + sizeof(char *); return lenTotal; } /** * Launches a JVM process and stores it internally. * * @return TRUE if there were any problems. When this happens the Wrapper will not try to restart. */ int wrapperExecute() { int i; pid_t proc; int execErrno; size_t lenCmd; size_t lenEnv; /* Create the pipe. */ if (pipe(pipedes) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Could not init pipe: %s"), getLastErrorText()); return TRUE; } /* Log the Java commands. */ /* If the JVM version printout is requested then log its command line first. */ if (wrapperData->printJVMVersion) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Java Command Line (Query Java Version):")); for (i = 0; wrapperData->jvmVersionCommand[i] != NULL; i++) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" Command[%d] : %s"), i, wrapperData->jvmVersionCommand[i]); } } } /* Log ghe application java command line */ if (wrapperData->commandLogLevel != LEVEL_NONE) { log_printf(WRAPPER_SOURCE_WRAPPER, wrapperData->commandLogLevel, TEXT("Java Command Line:")); for (i = 0; wrapperData->jvmCommand[i] != NULL; i++) { log_printf(WRAPPER_SOURCE_WRAPPER, wrapperData->commandLogLevel, TEXT(" Command[%d] : %s"), i, wrapperData->jvmCommand[i]); } if (wrapperData->environmentClasspath) { log_printf(WRAPPER_SOURCE_WRAPPER, wrapperData->commandLogLevel, TEXT(" Classpath in Environment : %s"), wrapperData->classpath); } } /* Update the CLASSPATH in the environment if requested so the JVM can access it. */ if (wrapperData->environmentClasspath) { setEnv(TEXT("CLASSPATH"), wrapperData->classpath, ENV_SOURCE_APPLICATION); } /* Make sure the log file is closed before the Java process is created. Failure to do * so will give the Java process a copy of the open file. This means that this process * will not be able to rename the file even after closing it because it will still be * open in the Java process. Also set the auto close flag to make sure that other * threads do not reopen the log file as the new process is being created. */ setLogfileAutoClose(TRUE); closeLogfile(); /* Reset the log duration so we get new counts from the time the JVM is launched. */ resetDuration(); /* Fork off the child. */ proc = fork(); if (proc == -1) { /* Fork failed. */ /* Restore the auto close flag. */ setLogfileAutoClose(wrapperData->logfileCloseTimeout == 0); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Could not spawn JVM process: %s"), getLastErrorText()); /* The pipedes array is global so do not close the pipes. */ return TRUE; } else { /* Reset the exit code when we launch a new JVM. */ wrapperData->exitCode = 0; /* Reset the stopped flag. */ wrapperData->jvmStopped = FALSE; if (proc == 0) { /* We are the child side. */ /* Set the umask of the JVM */ umask(wrapperData->javaUmask); /* The logging code causes some log corruption if logging is called from the * child of a fork. Not sure exactly why but most likely because the forked * child receives a copy of the mutex and thus synchronization is not working. * It is ok to log errors in here, but avoid output otherwise. * TODO: Figure out a way to fix this. Maybe using shared memory? */ /* Send output to the pipe by dupicating the pipe fd and setting the copy as the stdout fd. */ if (dup2(pipedes[PIPE_WRITE_END], STDOUT_FILENO) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("%sUnable to set JVM's stdout: %s"), LOG_FORK_MARKER, getLastErrorText()); /* This process needs to end. */ exit(1); return TRUE; /* Will not get here. */ } /* Send errors to the pipe by dupicating the pipe fd and setting the copy as the stderr fd. */ if (dup2(pipedes[PIPE_WRITE_END], STDERR_FILENO) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("%sUnable to set JVM's stderr: %s"), LOG_FORK_MARKER, getLastErrorText()); /* This process needs to end. */ exit(1); return TRUE; /* Will not get here. */ } /* Close both ends of the pipe as we have already duplicated the Write end for our purposes. */ close(pipedes[PIPE_READ_END]); pipedes[PIPE_READ_END] = -1; close(pipedes[PIPE_WRITE_END]); pipedes[PIPE_WRITE_END] = -1; /* forking at this point, the child process has set all pipes already, so no further assignments needed */ if (wrapperData->printJVMVersion) { if (fork() == 0) { /* in the child */ TCHAR *javaVersionArgv[3]; javaVersionArgv[0] = wrapperData->jvmCommand[0]; javaVersionArgv[1] = TEXT("-version"); javaVersionArgv[2] = 0; _texecvp(wrapperData->jvmCommand[0], javaVersionArgv); } /* we don't care about errors here, since they will be reported later */ } /* The pipedes array is global so do not close the pipes. */ /* Child process: execute the JVM. */ _texecvp(wrapperData->jvmCommand[0], wrapperData->jvmCommand); execErrno = errno; /* We reached this point...meaning we were unable to start. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("%sUnable to start JVM: %s (%d)"), LOG_FORK_MARKER, getLastErrorText(), execErrno); if (execErrno == E2BIG) { /* Command line too long. */ /* Calculate the total length of the command line. */ lenCmd = 0; for (i = 0; wrapperData->jvmCommand[i] != NULL; i++) { lenCmd += _tcslen(wrapperData->jvmCommand[i]) + 1; } lenEnv = wrapperCalculateEnvironmentLength(); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("%s The generated command line plus the environment was larger than the maximum allowed."), LOG_FORK_MARKER); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("%s The current length is %d bytes of which %d is the command line, and %d is the environment."), LOG_FORK_MARKER, lenCmd + lenEnv + 1, lenCmd, lenEnv); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("%s It is not possible to calculate an exact maximum length as it depends on a number of factors for each system."), LOG_FORK_MARKER); /* TODO: Figure out a way to inform the Wrapper not to restart and try again as repeatedly doing this is meaningless. */ } if (wrapperData->isAdviserEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%s"), LOG_FORK_MARKER ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%s------------------------------------------------------------------------"), LOG_FORK_MARKER ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%sAdvice:"), LOG_FORK_MARKER ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%sUsually when the Wrapper fails to start the JVM process, it is because"), LOG_FORK_MARKER ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%sof a problem with the value of the configured Java command. Currently:"), LOG_FORK_MARKER ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%swrapper.java.command=%s"), LOG_FORK_MARKER, getStringProperty(properties, TEXT("wrapper.java.command"), TEXT("java"))); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%sPlease make sure that the PATH or any other referenced environment"), LOG_FORK_MARKER ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%svariables are correctly defined for the current environment."), LOG_FORK_MARKER ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%s------------------------------------------------------------------------"), LOG_FORK_MARKER ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("%s"), LOG_FORK_MARKER ); } /* This process needs to end. */ exit(1); return TRUE; /* Will not get here. */ } else { /* We are the parent side and need to assume that at this point the JVM is up. */ wrapperData->javaPID = proc; /* Close the write end as it is not used. */ close(pipedes[PIPE_WRITE_END]); pipedes[PIPE_WRITE_END] = -1; /* Restore the auto close flag. */ setLogfileAutoClose(wrapperData->logfileCloseTimeout == 0); /* The pipedes array is global so do not close the pipes. */ /* Mark our side of the pipe so that it won't block * and will close on exec, so new children won't see it. */ if (fcntl(pipedes[PIPE_READ_END], F_SETFL, O_NONBLOCK) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to set JVM output handle to non blocking mode: %s (%d)"), getLastErrorText(), errno); } if (fcntl(pipedes[PIPE_READ_END], F_SETFD, FD_CLOEXEC) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to set JVM output handle to close on JVM exit: %s (%d)"), getLastErrorText(), errno); } /* If a java pid filename is specified then write the pid of the java process. */ if (wrapperData->javaPidFilename) { if (writePidFile(wrapperData->javaPidFilename, wrapperData->javaPID, wrapperData->javaPidFileUmask, FALSE)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to write the Java PID file: %s"), wrapperData->javaPidFilename); } } /* If a java id filename is specified then write the Id of the java process. */ if (wrapperData->javaIdFilename) { if (writePidFile(wrapperData->javaIdFilename, wrapperData->jvmRestarts, wrapperData->javaIdFileUmask, FALSE)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to write the Java Id file: %s"), wrapperData->javaIdFilename); } } return FALSE; } } } /** * Returns a tick count that can be used in combination with the * wrapperGetTickAgeSeconds() function to perform time keeping. */ TICKS wrapperGetTicks() { TICKS ticks; if (wrapperData->useSystemTime) { /* We want to return a tick count that is based on the current system time. */ ticks = wrapperGetSystemTicks(); } else { /* Lock the tick mutex whenever the "timerTicks" variable is accessed. */ if (wrapperData->useTickMutex && wrapperLockTickMutex()) { return 0; } /* Return a snapshot of the current tick count. */ ticks = timerTicks; if (wrapperData->useTickMutex && wrapperReleaseTickMutex()) { return 0; } } return ticks; } /** * Outputs a a log entry describing what the memory dump columns are. */ void wrapperDumpMemoryBanner() { /* Not yet implemented on UNIX platforms. */ } /** * Outputs a log entry at regular intervals to track the memory usage of the * Wrapper and its JVM. */ void wrapperDumpMemory() { struct rusage wUsage; struct rusage jUsage; if (getrusage(RUSAGE_SELF, &wUsage)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Call to getrusage failed for Wrapper process: %s"), getLastErrorText()); return; } /* The Children is only going to show the value for terminated children. */ if (getrusage(RUSAGE_CHILDREN, &jUsage)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Call to getrusage failed for Java process: %s"), getLastErrorText()); return; } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper Memory: maxrss=%ld, ixrss=%ld, idrss=%ld, isrss=%ld, minflt=%ld, majflt=%ld, nswap=%ld, inblock=%ld, oublock=%ld, msgsnd=%ld, msgrcv=%ld, nsignals=%ld, nvcsw=%ld, nvcsw=%ld"), wUsage.ru_maxrss, wUsage.ru_ixrss, wUsage.ru_idrss, wUsage.ru_isrss, wUsage.ru_minflt, wUsage.ru_majflt, wUsage.ru_nswap, wUsage.ru_inblock, wUsage.ru_oublock, wUsage.ru_msgsnd, wUsage.ru_msgrcv, wUsage.ru_nsignals, wUsage.ru_nvcsw, wUsage.ru_nvcsw); } /** * Outputs a log entry at regular intervals to track the CPU usage over each * interval for the Wrapper and its JVM. */ void wrapperDumpCPUUsage() { struct rusage wUsage; struct rusage jUsage; if (getrusage(RUSAGE_SELF, &wUsage)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Call to getrusage failed for Wrapper process: %s"), getLastErrorText()); return; } /* The Children is only going to show the value for terminated children. */ if (getrusage(RUSAGE_CHILDREN, &jUsage)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Call to getrusage failed for Java process: %s"), getLastErrorText()); return; } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper CPU: system %ld.%03ld, user %ld.%03ld Java CPU: system %ld.%03ld, user %ld.%03ld"), wUsage.ru_stime.tv_sec, wUsage.ru_stime.tv_usec / 1000, wUsage.ru_utime.tv_sec, wUsage.ru_utime.tv_usec / 1000, jUsage.ru_stime.tv_sec, jUsage.ru_stime.tv_usec / 1000, jUsage.ru_utime.tv_sec, jUsage.ru_utime.tv_usec / 1000); } /** * Checks on the status of the JVM Process. * Returns WRAPPER_PROCESS_UP or WRAPPER_PROCESS_DOWN */ int wrapperGetProcessStatus(TICKS nowTicks, int sigChild) { int retval; int status; int exitCode; int res; if (wrapperData->javaPID <= 0) { /* We do not think that a JVM is currently running so return that it is down. * If we call waitpid with 0, it will wait for any child and cause problems with the event commands. */ return WRAPPER_PROCESS_DOWN; } retval = waitpid(wrapperData->javaPID, &status, WNOHANG | WUNTRACED); if (retval == 0) { /* Up and running. */ if (sigChild && wrapperData->jvmStopped) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JVM process was continued.")); wrapperData->jvmStopped = FALSE; } res = WRAPPER_PROCESS_UP; } else if (retval < 0) { if (errno == ECHILD) { if ((wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED)) { res = WRAPPER_PROCESS_DOWN; wrapperJVMProcessExited(nowTicks, 0); return res; } else { /* Process is gone. Happens after a SIGCHLD is handled. Normal. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JVM process is gone.")); } } else { /* Error requesting the status. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to request JVM process status: %s"), getLastErrorText()); } exitCode = 1; res = WRAPPER_PROCESS_DOWN; wrapperJVMProcessExited(nowTicks, exitCode); } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" WIFEXITED=%d"), WIFEXITED(status)); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" WIFSTOPPED=%d"), WIFSTOPPED(status)); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" WIFSIGNALED=%d"), WIFSIGNALED(status)); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" WTERMSIG=%d"), WTERMSIG(status)); #endif /* Get the exit code of the process. */ if (WIFEXITED(status)) { /* JVM has exited. */ exitCode = WEXITSTATUS(status); res = WRAPPER_PROCESS_DOWN; wrapperJVMProcessExited(nowTicks, exitCode); } else if (WIFSIGNALED(status)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JVM received a signal %s (%d)."), getSignalName(WTERMSIG(status)), WTERMSIG(status)); res = WRAPPER_PROCESS_UP; } else if (WIFSTOPPED(status)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("JVM process was stopped. It will be killed if the ping timeout expires.")); wrapperData->jvmStopped = TRUE; res = WRAPPER_PROCESS_UP; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM process signaled the Wrapper unexpectedly.")); res = WRAPPER_PROCESS_UP; } } return res; } /** * This function does nothing on Unix machines. */ void wrapperReportStatus(int useLoggerQueue, int status, int errorCode, int waitHint) { return; } /** * Reads a single block of data from the child pipe. * * @param blockBuffer Pointer to the buffer where the block will be read. * @param blockSize Maximum number of bytes to read. * @param readCount Pointer to an int which will hold the number of bytes * actually read by the call. * * Returns TRUE if there were any problems, FALSE otherwise. */ int wrapperReadChildOutputBlock(char *blockBuffer, int blockSize, int *readCount) { if (pipedes[PIPE_READ_END] == -1) { /* The child is not up. */ *readCount = 0; return FALSE; } #if defined OPENBSD || defined FREEBSD /* Work around FreeBSD Bug #kern/64313 * http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/64313 * * When linked with the pthreads library the O_NONBLOCK flag is being reset * on the pipedes[PIPE_READ_END] handle. Not sure yet of the exact event that is causing * this, but once it happens reads will start to block even though calls * to fcntl(pipedes[PIPE_READ_END], F_GETFL) say that the O_NONBLOCK flag is set. * Calling fcntl(pipedes[PIPE_READ_END], F_SETFL, O_NONBLOCK) again will set the flag back * again and cause it to start working correctly. This may only need to * be done once, however, because F_GETFL does not return the accurate * state there is no reliable way to check. Be safe and always set the * flag. */ if (fcntl(pipedes[PIPE_READ_END], F_SETFL, O_NONBLOCK) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Failed to set JVM output handle to non blocking mode to read child process output: %s (%d)"), getLastErrorText(), errno); return TRUE; } #endif /* Fill read buffer. */ *readCount = read(pipedes[PIPE_READ_END], blockBuffer, blockSize); if (*readCount < 0) { /* No more bytes available, return for now. But make sure that this was not an error. */ if (errno == EAGAIN) { /* Normal, the call would have blocked as there is no data available. */ } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Failed to read console output from the JVM: %s (%d)"), getLastErrorText(), errno); return TRUE; } } else if (*readCount == 0) { /* We reached the EOF. This means that the other end of the pipe was closed. */ close(pipedes[PIPE_READ_END]); pipedes[PIPE_READ_END] = -1; } return FALSE; } /** * Transform a program into a daemon. * * The idea is to first fork, then make the child a session leader, * and then fork again, so that it, (the session group leader), can * exit. This means that we, the grandchild, as a non-session group * leader, can never regain a controlling terminal. */ void daemonize(int argc, TCHAR** argv) { pid_t pid; int fd; /* Set the auto close flag and close the logfile before doing any forking to avoid * duplicate open files. */ setLogfileAutoClose(TRUE); closeLogfile(); /* first fork */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Spawning intermediate process...")); } if ((pid = fork()) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Could not spawn daemon process: %s"), getLastErrorText()); appExit(1, argc, argv); } else if (pid != 0) { /* Intermediate process is now running. This is the original process, so exit. */ /* If the main process was not launched in the background, then we want to make * the console output look nice by making sure that all output from the * intermediate and daemon threads are complete before this thread exits. * Sleep for 0.5 seconds. */ wrapperSleep(500); /* Call exit rather than appExit as we are only exiting this process. */ exit(0); } /* become session leader */ if (setsid() == -1) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("setsid() failed: %s"), getLastErrorText()); appExit(1, argc, argv); } signal(SIGHUP, SIG_IGN); /* don't let future opens allocate controlling terminals */ /* Redirect stdin, stdout and stderr before closing to prevent the shell which launched * the Wrapper from hanging when it exits. */ fd = _topen(TEXT("/dev/null"), O_RDWR, 0); if (fd != -1) { close(STDIN_FILENO); dup2(fd, STDIN_FILENO); close(STDOUT_FILENO); dup2(fd, STDOUT_FILENO); close(STDERR_FILENO); dup2(fd, STDERR_FILENO); if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) { close(fd); } } /* Console output was disabled above, so make sure the console log output is disabled * so we don't waste any CPU formatting and sending output to '/dev/null'/ */ setConsoleLogLevelInt(LEVEL_NONE); /* second fork */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Spawning daemon process...")); } if ((pid = fork()) < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Could not spawn daemon process: %s"), getLastErrorText()); appExit(1, argc, argv); } else if (pid != 0) { /* Daemon process is now running. This is the intermediate process, so exit. */ /* Call exit rather than appExit as we are only exiting this process. */ exit(0); } /* Restore the auto close flag in the daemonized process. */ setLogfileAutoClose(wrapperData->logfileCloseTimeout == 0); } /** * Sets the working directory to that of the current executable */ int setWorkingDir(TCHAR *app) { TCHAR *szPath; TCHAR* pos; /* Get the full path and filename of this program */ if ((szPath = findPathOf(app, TEXT("Wrapper binary"))) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to get the path for '%s'-%s"), app, getLastErrorText()); return 1; } /* The wrapperData->isDebugging flag will never be set here, so we can't really use it. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Executable Name: %s"), szPath); #endif /* To get the path, strip everything off after the last '\' */ pos = _tcsrchr(szPath, TEXT('/')); if (pos == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to extract path from: %s"), szPath); free(szPath); return 1; } else { /* Clip the path at the position of the last backslash */ pos[0] = (TCHAR)0; } /* Set a variable to the location of the binary. */ setEnv(TEXT("WRAPPER_BIN_DIR"), szPath, ENV_SOURCE_APPLICATION); if (wrapperSetWorkingDir(szPath, TRUE)) { free(szPath); return 1; } free(szPath); return 0; } /******************************************************************************* * Main function * *******************************************************************************/ #ifndef CUNIT #ifdef UNICODE int main(int argc, char **cargv) { #else int main(int argc, char **argv) { #endif #if defined(_DEBUG) || defined(UNICODE) int i; #endif TCHAR *retLocale; #ifdef UNICODE size_t req; TCHAR **argv; #ifdef FREEBSD /* In the case of FreeBSD, we need to dynamically load and initialize the iconv library to work with all versions of FreeBSD. */ if (loadIconvLibrary()) { /* Already reported. */ /* Don't call appExit here as we are not far enough along. */ return 1; } #endif /* we should set the locale before trying to convert cargv to argv, * because there might be accentued letter in cargv */ retLocale = _tsetlocale(LC_ALL, TEXT("")); if (retLocale) { #if defined(UNICODE) free(retLocale); #endif } else { /* TODO - We need to be careful about LANG here as it is not set on all systems. */ /* envLang = _tgetenv(TEXT("LANG")); _tprintf(TEXT("Can't set the locale(%s); make sure $LC_* and $LANG are correct.\n"), envLang); #if defined(UNICODE) free(envLang); #endif */ } /* Create UNICODE versions of the argv array for internal use. */ argv = malloc(argc * sizeof(TCHAR *)); if (!argv) { _tprintf(TEXT("Out of Memory in Main\n")); appExit(1, 0, NULL); return 1; } for (i = 0; i < argc; i++) { req = mbstowcs(NULL, cargv[i], MBSTOWCS_QUERY_LENGTH); if (req == (size_t)-1) { _tprintf(TEXT("Encoding problem with arguments in Main\n")); free(argv); appExit(1, 0, NULL); return 1; } argv[i] = malloc(sizeof(TCHAR) * (req + 1)); if (!argv[i]) { _tprintf(TEXT("Out of Memory in Main\n")); while (--i > 0) { free(argv[i]); } free(argv); appExit(1, 0, NULL); return 1; } mbstowcs(argv[i], cargv[i], req + 1); argv[i][req] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ } #endif if (wrapperInitialize()) { appExit(1, argc, argv); return 1; /* For compiler. */ } /* Main thread initialized in wrapperInitialize. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper DEBUG build!")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Logging initialized.")); #endif /* Get the current process. */ wrapperData->wrapperPID = getpid(); if (setWorkingDir(argv[0])) { appExit(1, argc, argv); return 1; /* For compiler. */ } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Working directory set.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Arguments:")); for (i = 0; i < argc; i++) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" argv[%d]=%s"), i, argv[i]); } #endif /* Parse the command and configuration file from the command line. */ if (!wrapperParseArguments(argc, argv)) { appExit(1, argc, argv); return 1; /* For compiler. */ } wrapperLoadHostName(); if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("-translate"))) { /* We want to disable all log output when a translation request is made. */ setSilentLogLevels(); } /* At this point, we have a command, confFile, and possibly additional arguments. */ if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("?")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-help"))) { /* User asked for the usage. */ setSimpleLogLevels(); wrapperUsage(argv[0]); appExit(0, argc, argv); return 0; /* For compiler. */ } else if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("v")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-version"))) { /* User asked for version. */ setSimpleLogLevels(); wrapperVersionBanner(); appExit(0, argc, argv); return 0; /* For compiler. */ } else if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("h")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-hostid"))) { /* User asked for version. */ setSimpleLogLevels(); wrapperVersionBanner(); showHostIds(LEVEL_STATUS); appExit(0, argc, argv); return 0; /* For compiler. */ } /* Load the properties. */ if (wrapperLoadConfigurationProperties(FALSE)) { /* Unable to load the configuration. Any errors will have already * been reported. */ if (wrapperData->argConfFileDefault && !wrapperData->argConfFileFound) { /* The config file that was being looked for was default and * it did not exist. Show the usage. */ wrapperUsage(argv[0]); } appExit(1, argc, argv); return 1; /* For compiler. */ } /* Set the default umask of the Wrapper process. */ umask(wrapperData->umask); if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("-translate"))) { setSimpleLogLevels(); /* Print out the string so the caller sees it as its translated output. */ _tprintf(TEXT("%s"), argv[2]); appExit(0, argc, argv); return 0; /* For compiler. */ } else if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("c")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-console"))) { /* Run as a console application */ /* fork to a Daemonized process if configured to do so. */ if (wrapperData->daemonize) { daemonize(argc, argv); /* We are now daemonized, so mark this as being a service. */ wrapperData->isConsole = FALSE; /* When we daemonize the Wrapper, its PID changes. Because of the * WRAPPER_PID environment variable, we need to set it again here * and then reload the configuration in case the PID is referenced * in the configuration. */ /* Get the current process. */ wrapperData->wrapperPID = getpid(); if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Reloading configuration.")); } /* If the working dir has been changed then we need to restore it before * the configuration can be reloaded. This is needed to support relative * references to include files. */ if (wrapperData->workingDir && wrapperData->originalWorkingDir) { if (wrapperSetWorkingDir(wrapperData->originalWorkingDir, TRUE)) { /* Failed to restore the working dir. Shutdown the Wrapper */ appExit(1, argc, argv); return 1; /* For compiler. */ } } /* Load the properties. */ if (wrapperLoadConfigurationProperties(FALSE)) { /* Unable to load the configuration. Any errors will have already * been reported. */ if (wrapperData->argConfFileDefault && !wrapperData->argConfFileFound) { /* The config file that was being looked for was default and * it did not exist. Show the usage. */ wrapperUsage(argv[0]); } appExit(1, argc, argv); return 1; /* For compiler. */ } } /* See if the logs should be rolled on Wrapper startup. */ if ((getLogfileRollMode() & ROLL_MODE_WRAPPER) || (getLogfileRollMode() & ROLL_MODE_JVM)) { rollLogs(); } if (wrapperData->pidFilename) { if (writePidFile(wrapperData->pidFilename, wrapperData->wrapperPID, wrapperData->pidFileUmask, wrapperData->pidFileStrict)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not write pid file %s: %s"), wrapperData->pidFilename, getLastErrorText()); /* Common wrapper cleanup code. */ wrapperDispose(); #if defined(UNICODE) for (i = 0; i < argc; i++) { if (argv[i]) { free(argv[i]); } } if (argv) { free(argv); } #endif exit(1); return 1; /* For compiler. */ } } /* Write pid and anchor files as requested. If they are the same file the file is * simply overwritten. */ if (wrapperData->anchorFilename) { if (writePidFile(wrapperData->anchorFilename, wrapperData->wrapperPID, wrapperData->anchorFileUmask, FALSE)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not write anchor file %s: %s"), wrapperData->anchorFilename, getLastErrorText()); appExit(1, argc, argv); return 1; /* For compiler. */ } } if (wrapperData->lockFilename) { if (writePidFile(wrapperData->lockFilename, wrapperData->wrapperPID, wrapperData->lockFileUmask, FALSE)) { /* This will fail if the user is running as a user without full privileges. * To make things easier for user configuration, this is ignored if sufficient * privileges do not exist. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("WARNING: Could not write lock file %s: %s"), wrapperData->lockFilename, getLastErrorText()); wrapperData->lockFilename = NULL; } } if (wrapperData->isConsole) { appExit(wrapperRunConsole(), argc, argv); } else { appExit(wrapperRunService(), argc, argv); } return 0; /* For compiler. */ } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unrecognized option: -%s"), wrapperData->argCommand); wrapperUsage(argv[0]); appExit(1, argc, argv); return 1; /* For compiler. */ } } #endif #endif /* ifndef WIN32 */ wrapper_3.5.26_src/src/c/wrapper_win.c100644 0 0 1115444 12440202301 15137 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * Author: * Leif Mortenson */ #ifdef WIN32 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psapi.h" #include "wrapper_i18n.h" #include "resource.h" #include "wrapper.h" #include "wrapperinfo.h" #include "property.h" #include "logger.h" #include "wrapper_file.h" /* The largest possible command line length on Windows. */ #define MAX_COMMAND_LINE_LEN 32766 #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) typedef struct { LPWSTR lpszProgramName; LPWSTR lpszPublisherLink; LPWSTR lpszMoreInfoLink; } SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO; #ifndef POLICY_AUDIT_SUBCATEGORY_COUNT /* The current SDK is pre-Vista. Add the required definitions. */ typedef struct _TOKEN_ELEVATION { DWORD TokenIsElevated; } TOKEN_ELEVATION, *PTOKEN_ELEVATION; #define TokenElevation TokenOrigin + 3 #endif /***************************************************************************** * Win32 specific variables and procedures * *****************************************************************************/ SERVICE_STATUS ssStatus; SERVICE_STATUS_HANDLE sshStatusHandle; #define SYSTEM_PATH_MAX_LEN 256 static TCHAR *systemPath[SYSTEM_PATH_MAX_LEN]; static HANDLE wrapperChildStdoutWr = INVALID_HANDLE_VALUE; static HANDLE wrapperChildStdoutRd = INVALID_HANDLE_VALUE; TCHAR wrapperClasspathSeparator = TEXT(';'); HANDLE startupThreadHandle; DWORD startupThreadId; int startupThreadStarted = FALSE; int startupThreadStopped = FALSE; HANDLE javaIOThreadHandle; DWORD javaIOThreadId; int javaIOThreadStarted = FALSE; int stopJavaIOThread = FALSE; int javaIOThreadStopped = FALSE; HANDLE timerThreadHandle; DWORD timerThreadId; int timerThreadStarted = FALSE; int stopTimerThread = FALSE; int timerThreadStopped = FALSE; TICKS timerTicks = WRAPPER_TICK_INITIAL; /** Flag which keeps track of whether or not the CTRL-C key has been pressed. */ int ctrlCTrapped = FALSE; /** Flag which keeps track of whether or not PID files should be deleted on shutdown. */ int cleanUpPIDFilesOnExit = FALSE; TCHAR* getExceptionName(DWORD exCode); /* Dynamically loadedfunction types. */ typedef SERVICE_STATUS_HANDLE(*FTRegisterServiceCtrlHandlerEx)(LPCTSTR, LPHANDLER_FUNCTION_EX, LPVOID); /* Dynamically loaded functions. */ FARPROC OptionalGetProcessTimes = NULL; FARPROC OptionalGetProcessMemoryInfo = NULL; FTRegisterServiceCtrlHandlerEx OptionalRegisterServiceCtrlHandlerEx = NULL; /****************************************************************************** * Windows specific code ******************************************************************************/ PDH_HQUERY pdhQuery = NULL; PDH_HCOUNTER pdhCounterPhysicalDiskAvgQueueLen = NULL; PDH_HCOUNTER pdhCounterPhysicalDiskAvgWriteQueueLen = NULL; PDH_HCOUNTER pdhCounterPhysicalDiskAvgReadQueueLen = NULL; PDH_HCOUNTER pdhCounterMemoryPageFaultsPSec = NULL; PDH_HCOUNTER pdhCounterMemoryTransitionFaultsPSec = NULL; PDH_HCOUNTER pdhCounterProcessWrapperPageFaultsPSec = NULL; PDH_HCOUNTER pdhCounterProcessJavaPageFaultsPSec = NULL; #define FILEPATHSIZE 1024 /** * Tests whether or not the current OS is at or below the version of Windows NT. * * @return TRUE if NT 4.0 or earlier, FALSE otherwise. */ BOOL isWindowsNT4_0OrEarlier() { OSVERSIONINFOEX osvi; BOOL bOsVersionInfoEx; BOOL retval; /* Try calling GetVersionEx using the OSVERSIONINFOEX structure. * If that fails, try using the OSVERSIONINFO structure. */ retval = TRUE; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *)&osvi))) { /* If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. */ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx((OSVERSIONINFO *)&osvi)) { retval = TRUE; } } if (osvi.dwMajorVersion <= 4) { retval = TRUE; } else { retval = FALSE; } return retval; } #ifdef _UNICODE #define FUNCTION_NAME_RegisterServiceCtrlHandlerEx "RegisterServiceCtrlHandlerExW" #else #define FUNCTION_NAME_RegisterServiceCtrlHandlerEx "RegisterServiceCtrlHandlerExA" #endif void loadDLLProcs() { HMODULE kernel32Mod; HMODULE psapiMod; HMODULE advapi32Mod; /* The KERNEL32 module was added in NT 3.5. */ if ((kernel32Mod = GetModuleHandle(TEXT("KERNEL32.DLL"))) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The KERNEL32.DLL was not found. Some functions will be disabled.")); } else { if ((OptionalGetProcessTimes = GetProcAddress(kernel32Mod, "GetProcessTimes")) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The GetProcessTimes is not available in this KERNEL32.DLL version. Some functions will be disabled.")); } } /* The PSAPI module was added in NT 4.0. */ if ((psapiMod = LoadLibrary(TEXT("PSAPI.DLL"))) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The PSAPI.DLL was not found. Some functions will be disabled.")); } else { if ((OptionalGetProcessMemoryInfo = GetProcAddress(psapiMod, "GetProcessMemoryInfo")) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The GetProcessMemoryInfo is not available in this PSAPI.DLL version. Some functions will be disabled.")); } } /* The ADVAPI32 module was added in NT 5.0. */ if ((advapi32Mod = LoadLibrary(TEXT("ADVAPI32.DLL"))) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The ADVAPI32.DLL was not found. Some functions will be disabled.")); } else { if ((OptionalRegisterServiceCtrlHandlerEx = (FTRegisterServiceCtrlHandlerEx)GetProcAddress(advapi32Mod, FUNCTION_NAME_RegisterServiceCtrlHandlerEx)) == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The %s is not available in this ADVAPI32.DLL version. Some functions will be disabled."), FUNCTION_NAME_RegisterServiceCtrlHandlerEx); } } } /** * Builds an array in memory of the system path. */ int buildSystemPath() { TCHAR *envBuffer; size_t len, i; TCHAR *c, *lc; /* Get the length of the PATH environment variable. */ len = GetEnvironmentVariable(TEXT("PATH"), NULL, 0); if (len == 0) { /* PATH not set on this system. Not an error. */ systemPath[0] = NULL; return 0; } /* Allocate the memory to hold the PATH */ envBuffer = malloc(sizeof(TCHAR) * len); if (!envBuffer) { outOfMemory(TEXT("BSP"), 1); return 1; } GetEnvironmentVariable(TEXT("PATH"), envBuffer, (DWORD)len); #ifdef _DEBUG _tprintf(TEXT("Getting the system path: %s\n"), envBuffer); #endif /* Build an array of the path elements. To make it easy, just * assume there won't be more than 255 path elements. Verified * in the loop. */ i = 0; lc = envBuffer; /* Get the elements ending in a ';' */ while (((c = _tcschr(lc, TEXT(';'))) != NULL) && (i < SYSTEM_PATH_MAX_LEN - 2)) { len = (int)(c - lc); systemPath[i] = malloc(sizeof(TCHAR) * (len + 1)); if (!systemPath[i]) { outOfMemory(TEXT("BSP"), 2); return 1; } memcpy(systemPath[i], lc, sizeof(TCHAR) * len); systemPath[i][len] = TEXT('\0'); #ifdef _DEBUG _tprintf(TEXT("PATH[%d]=%s\n"), i, systemPath[i]); #endif lc = c + 1; i++; } /* There should be one more value after the last ';' */ len = _tcslen(lc); systemPath[i] = malloc(sizeof(TCHAR) * (len + 1)); if (!systemPath[i]) { outOfMemory(TEXT("BSP"), 3); return 1; } _tcsncpy(systemPath[i], lc, len + 1); #ifdef _DEBUG _tprintf(TEXT("PATH[%d]=%s\n"), i, systemPath[i]); #endif i++; /* NULL terminate the array. */ systemPath[i] = NULL; #ifdef _DEBUG _tprintf(TEXT("PATH[%d]=\n"), i); #endif i++; /* Release the environment variable memory. */ free(envBuffer); return 0; } TCHAR** wrapperGetSystemPath() { return systemPath; } /** * Initializes the invocation mutex. Returns 1 if the mutex already exists * or can not be created. 0 if this is the first instance. */ HANDLE invocationMutexHandle = NULL; int initInvocationMutex() { TCHAR *mutexName; if (wrapperData->isSingleInvocation) { mutexName = malloc(sizeof(TCHAR) * (30 + _tcslen(wrapperData->serviceName) + 1)); if (!mutexName) { outOfMemory(TEXT("IIM"), 1); return 1; } _sntprintf(mutexName, 30 + _tcslen(wrapperData->serviceName) + 1, TEXT("Global\\Java Service Wrapper - %s"), wrapperData->serviceName); if (!(invocationMutexHandle = CreateMutex(NULL, FALSE, mutexName))) { free(mutexName); if (GetLastError() == ERROR_ACCESS_DENIED) { /* Most likely the app is running as a service and we tried to run it as a console. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("ERROR: Another instance of the %s application is already running."), wrapperData->serviceName); return 1; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Unable to create the single invocation mutex. %s"), getLastErrorText()); return 1; } } else { free(mutexName); } if (GetLastError() == ERROR_ALREADY_EXISTS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("ERROR: Another instance of the %s application is already running."), wrapperData->serviceName); return 1; } } return 0; } /** * exits the application after running shutdown code. */ void appExit(int exitCode) { /* We only want to delete the pid files if we created them. Some Wrapper * invocations are meant to run in parallel with Wrapper instances * controlling a JVM. */ if (cleanUpPIDFilesOnExit) { /* Remove pid file. It may no longer exist. */ if (wrapperData->pidFilename) { _tunlink(wrapperData->pidFilename); } /* Remove lock file. It may no longer exist. */ if (wrapperData->lockFilename) { _tunlink(wrapperData->lockFilename); } /* Remove status file. It may no longer exist. */ if (wrapperData->statusFilename) { _tunlink(wrapperData->statusFilename); } /* Remove java status file if it was registered and created by this process. */ if (wrapperData->javaStatusFilename) { _tunlink(wrapperData->javaStatusFilename); } /* Remove java id file if it was registered and created by this process. */ if (wrapperData->javaIdFilename) { _tunlink(wrapperData->javaIdFilename); } /* Remove anchor file. It may no longer exist. */ if (wrapperData->anchorFilename) { _tunlink(wrapperData->anchorFilename); } } /* Close the invocation mutex if we created or looked it up. */ if (invocationMutexHandle) { CloseHandle(invocationMutexHandle); invocationMutexHandle = NULL; } /* Common wrapper cleanup code. */ wrapperDispose(); /* Do this here to unregister the syslog resources on exit.*/ /*unregisterSyslogMessageFile(); */ exit(exitCode); } /** * Writes the specified Id or PID to disk. * * filename: File to write to. * pid: pid to write in the file. * strict: If true then an error will be reported and the call will fail if the * file already exists. * * return 1 if there was an error, 0 if Ok. */ int writePidFile(const TCHAR *filename, DWORD pid, int newUmask, int strict) { FILE *pid_fp = NULL; int old_umask; if (strict && wrapperFileExists(filename)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("%d pid file, %s, already exists."), pid, filename); cleanUpPIDFilesOnExit = FALSE; return 1; } old_umask = _umask(newUmask); pid_fp = _tfopen(filename, TEXT("w")); _umask(old_umask); if (pid_fp != NULL) { _ftprintf(pid_fp, TEXT("%d\n"), pid); fclose(pid_fp); } else { return 1; } return 0; } /** * Initialize the pipe which will be used to capture the output from the child * process. */ int wrapperInitChildPipe() { SECURITY_ATTRIBUTES saAttr; HANDLE childStdoutRd = INVALID_HANDLE_VALUE; /* Set the bInheritHandle flag so pipe handles are inherited. */ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.lpSecurityDescriptor = NULL; saAttr.bInheritHandle = TRUE; /* Create a pipe for the child process's STDOUT. */ if (!CreatePipe(&childStdoutRd, &wrapperChildStdoutWr, &saAttr, wrapperData->javaIOBufferSize)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Stdout pipe creation failed Err(%ld : %s)"), GetLastError(), getLastErrorText()); return -1; } /* Create a noninheritable read handle and close the inheritable read handle. */ if (!DuplicateHandle(GetCurrentProcess(), childStdoutRd, GetCurrentProcess(), &wrapperChildStdoutRd, 0, FALSE, DUPLICATE_SAME_ACCESS)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("DuplicateHandle failed")); return -1; } CloseHandle(childStdoutRd); return 0; } /** * Handler to take care of the case where the user hits CTRL-C when the wrapper * is being run as a console. * * Handlers are called in the reverse order that they are registered until one * returns TRUE. So last registered is called first until the default handler * is called. */ int wrapperConsoleHandler(int key) { /* Immediately register this thread with the logger. */ logRegisterThread(WRAPPER_THREAD_SIGNAL); /* Enclose the contents of this call in a try catch block so we can * display and log useful information should the need arise. */ __try { switch (key) { case CTRL_C_EVENT: /* The user hit CTRL-C. Can only happen when run as a console. */ if (wrapperData->ignoreSignals & WRAPPER_IGNORE_SIGNALS_WRAPPER) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("CTRL-C trapped, but ignored.")); } else { wrapperData->ctrlEventCTRLCTrapped = TRUE; } break; case CTRL_CLOSE_EVENT: /* The user tried to close the console. Can only happen when run as a console. */ if (wrapperData->ignoreSignals & WRAPPER_IGNORE_SIGNALS_WRAPPER) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Close trapped, but ignored.")); } else { wrapperData->ctrlEventCloseTrapped = TRUE; } break; case CTRL_BREAK_EVENT: /* The user hit CTRL-BREAK */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("CTRL-BREAK/PAUSE trapped. Asking the JVM to dump its state.")); /* If the java process was launched using the same console, ie where * processflags=CREATE_NEW_PROCESS_GROUP; then the java process will * also get this message, so it can be ignored here. */ /* If we ever do something here, remember that this can't be called directly from here. wrapperRequestDumpJVMState(); */ break; case CTRL_LOGOFF_EVENT: wrapperData->ctrlEventLogoffTrapped = TRUE; break; case CTRL_SHUTDOWN_EVENT: wrapperData->ctrlEventShutdownTrapped = TRUE; break; default: /* Unknown. Don't quit here. */ log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Trapped unexpected console signal (%d). Ignored."), key); } } __except (exceptionFilterFunction(GetExceptionInformation())) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("<-- Wrapper Stopping due to error in console handler.")); appExit(1); } return TRUE; /* We handled the event. */ } /****************************************************************************** * Platform specific methods *****************************************************************************/ /** * Send a signal to the JVM process asking it to dump its JVM state. */ void wrapperRequestDumpJVMState() { if (wrapperData->javaProcess != NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Dumping JVM state.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Sending BREAK event to process group %ld."), wrapperData->javaPID); if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, wrapperData->javaPID) == 0) { if (wrapperData->generateConsole) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to send BREAK event to JVM process to generate a thread dump. Err(%ld : %s)"), GetLastError(), getLastErrorText()); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to send BREAK event to JVM process to generate a thread dump because a console does not exist.\n Please see the wrapper.ntservice.generate_console property.")); } } } } /** * Build the java command line. * * @return TRUE if there were any problems. */ int wrapperBuildJavaCommand() { size_t commandLen; size_t commandLen2; TCHAR **strings; int length; int i; /* If this is not the first time through, then dispose the old command */ if (wrapperData->jvmCommand) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Clearing up old command line")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Old Command Line \"%s\""), wrapperData->jvmCommand); #endif free(wrapperData->jvmCommand); wrapperData->jvmCommand = NULL; } /* First generate the classpath. */ if (wrapperData->classpath) { free(wrapperData->classpath); wrapperData->classpath = NULL; } if (wrapperBuildJavaClasspath(&wrapperData->classpath) < 0) { return TRUE; } /* Build the Java Command Strings */ strings = NULL; length = 0; if (wrapperBuildJavaCommandArray(&strings, &length, TRUE, wrapperData->classpath)) { /* Failed. */ return TRUE; } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM Command Line Parameters")); for (i = 0; i < length; i++) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%d : %s"), i, strings[i]); } #endif /* Build a single string from the array that will be used to request the Java version. * The first element of the command array will always be the java binary. */ /* Calculate the length */ commandLen = _tcslen(strings[0]); commandLen += 1; /* Space */ commandLen += _tcslen(TEXT("-version")); commandLen++; /* '\0' */ /* Build the actual command */ wrapperData->jvmVersionCommand = malloc(sizeof(TCHAR) * commandLen); if (!wrapperData->jvmVersionCommand) { outOfMemory(TEXT("WBJC"), 1); return TRUE; } _sntprintf(wrapperData->jvmVersionCommand, commandLen, TEXT("%s -version"), strings[0]); /* Build a single string from the array */ /* Calculate the length */ commandLen = 0; for (i = 0; i < length; i++) { if (i > 0) { commandLen++; /* Space */ } commandLen += _tcslen(strings[i]); } commandLen++; /* '\0' */ commandLen2 = commandLen; /* Build the actual command */ wrapperData->jvmCommand = malloc(sizeof(TCHAR) * commandLen2); if (!wrapperData->jvmCommand) { outOfMemory(TEXT("WBJC"), 2); return TRUE; } commandLen = 0; for (i = 0; i < length; i++) { if (i > 0) { wrapperData->jvmCommand[commandLen++] = TEXT(' '); } _sntprintf(wrapperData->jvmCommand + commandLen, commandLen2 - commandLen, TEXT("%s"), strings[i]); commandLen += _tcslen(strings[i]); } wrapperData->jvmCommand[commandLen++] = TEXT('\0'); wrapperData->jvmCommand = wrapperPostProcessCommandElement(wrapperData->jvmCommand); /* Free up the temporary command array */ wrapperFreeJavaCommandArray(strings, length); return FALSE; } int hideConsoleWindow(HWND consoleHandle, const TCHAR *name) { WINDOWPLACEMENT consolePlacement; memset(&consolePlacement, 0, sizeof(WINDOWPLACEMENT)); consolePlacement.length = sizeof(WINDOWPLACEMENT); if (IsWindowVisible(consoleHandle)) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s console window is visible, attempt to hide."), name); #endif /* Hide the Window. */ consolePlacement.showCmd = SW_HIDE; if (!SetWindowPlacement(consoleHandle, &consolePlacement)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to set window placement information: %s"), getLastErrorText()); } if (IsWindowVisible(consoleHandle)) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Failed to hide the %s console window."), name); } return FALSE; } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s console window hidden successfully."), name); } return TRUE; } } else { /* Already hidden */ return TRUE; } } /** * Look for and hide the wrapper or JVM console windows if they should be hidden. * Some users have reported that if the user logs on to windows quickly after booting up, * the console window will be redisplayed even though it was hidden once. The forceCheck * will continue to attempt to check and hide the window if this does happen for up to a * predetermined period of time. */ void wrapperCheckConsoleWindows() { int forceCheck = TRUE; /* See if the Wrapper console needs to be hidden. */ if (wrapperData->wrapperConsoleHide && (wrapperData->wrapperConsoleHWND != NULL) && (wrapperData->wrapperConsoleVisible || forceCheck)) { if (hideConsoleWindow(wrapperData->wrapperConsoleHWND, TEXT("Wrapper"))) { wrapperData->wrapperConsoleVisible = FALSE; } } /* See if the Java console needs to be hidden. */ if ((wrapperData->jvmConsoleHandle != NULL) && (wrapperData->jvmConsoleVisible || forceCheck)) { if (hideConsoleWindow(wrapperData->jvmConsoleHandle, TEXT("JVM"))) { wrapperData->jvmConsoleVisible = FALSE; } } } HWND findConsoleWindow( TCHAR *title ) { HWND consoleHandle; int i = 0; /* Allow up to 2 seconds for the window to show up, but don't hang * up if it doesn't */ consoleHandle = NULL; while ((!consoleHandle) && (i < 200)) { wrapperSleep(10); consoleHandle = FindWindow(TEXT("ConsoleWindowClass"), title); i++; } return consoleHandle; } void showConsoleWindow(HWND consoleHandle, const TCHAR *name) { WINDOWPLACEMENT consolePlacement; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Show %s console window with which JVM is launched."), name); } if (GetWindowPlacement(consoleHandle, &consolePlacement)) { /* Show the Window. */ consolePlacement.showCmd = SW_SHOW; if (!SetWindowPlacement(consoleHandle, &consolePlacement)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to set window placement information: %s"), getLastErrorText()); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to obtain window placement information: %s"), getLastErrorText()); } } /** * The main entry point for the startup thread which is started by * wrapperRunCommon(). Once started, this thread will run for the * life of the startup and then exit. * * This thread only exists so that certain tasks which take an * undetermined amount of time can run without affecting the startup * time of the Wrapper. */ DWORD WINAPI startupRunner(LPVOID parameter) { /* In case there are ever any problems in this thread, enclose it in a try catch block. */ __try { startupThreadStarted = TRUE; /* Immediately register this thread with the logger. */ logRegisterThread(WRAPPER_THREAD_STARTUP); if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s thread started."), TEXT("Startup")); } if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Attempting to verify the binary signature.")); } verifyEmbeddedSignature(); } __except (exceptionFilterFunction(GetExceptionInformation())) { /* This call is not queued to make sure it makes it to the log prior to a shutdown. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Fatal error in the %s thread."), TEXT("Startup")); startupThreadStopped = TRUE; /* Before appExit() */ appExit(1); return 1; /* For the compiler, we will never get here. */ } startupThreadStopped = TRUE; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s thread stopped."), TEXT("Startup")); } return 0; } /** * Creates a thread whose job is to process some startup actions which could take a while to * complete. This function will automatically wait for a configured length of time for the * thread to complete. If it does not complete within the predetermined amount of time then * it will continue to avoid slowing down the Wrapper startup. * * This startup timeout can be controlled with the wrapper.startup_thread.timeout property. */ int initializeStartup() { int startupThreadTimeout; TICKS nowTicks; TICKS timeoutTicks; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Launching %s thread."), TEXT("Startup")); } startupThreadHandle = CreateThread( NULL, /* No security attributes as there will not be any child processes of the thread. */ 0, /* Use the default stack size. */ startupRunner, NULL, /* No parameters need to passed to the thread. */ 0, /* Start the thread running immediately. */ &startupThreadId); if (!startupThreadHandle) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to create a %s thread: %s"), TEXT("Startup"), getLastErrorText()); return 1; } /* Wait until the startup thread completes or the timeout expires. */ startupThreadTimeout = propIntMin(propIntMax(getIntProperty(properties, TEXT("wrapper.startup_thread.timeout"), 2), 0), 3600); nowTicks = wrapperGetTicks(); timeoutTicks = wrapperAddToTicks(nowTicks, startupThreadTimeout); while ((!startupThreadStopped) && (wrapperGetTickAgeSeconds(timeoutTicks, nowTicks) < 0)) { #if DEBUG_STARTUP log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" Waiting for startup... %08x < %08x"), nowTicks, timeoutTicks); #endif wrapperSleep(10); nowTicks = wrapperGetTicks(); } if (startupThreadStopped) { #if DEBUG_STARTUP log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s completed."), TEXT("Startup")); #endif if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { appExit(1); } } else { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s timed out. Continuing in background."), TEXT("Startup")); } } return 0; } void disposeStartup() { /* Wait until the javaIO thread is actually stopped to avoid timing problems. */ if (startupThreadStarted && !startupThreadStopped) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Waiting for %s thread to complete..."), TEXT("Startup")); } while (!startupThreadStopped) { #ifdef _DEBUG wprintf(TEXT("Waiting for %s thread to stop.\n"), TEXT("Startup")); #endif wrapperSleep(100); } } } /** * The main entry point for the javaio thread which is started by * initializeJavaIO(). Once started, this thread will run for the * life of the process. * * This thread will only be started if we are configured to use a * dedicated thread to read JVM output. */ DWORD WINAPI javaIORunner(LPVOID parameter) { int nextSleep; /* In case there are ever any problems in this thread, enclose it in a try catch block. */ __try { javaIOThreadStarted = TRUE; /* Immediately register this thread with the logger. */ logRegisterThread(WRAPPER_THREAD_JAVAIO); if (wrapperData->isJavaIOOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s thread started."), TEXT("JavaIO")); } nextSleep = TRUE; /* Loop until we are shutting down, but continue as long as there is more output from the JVM. */ while ((!stopJavaIOThread) || (!nextSleep)) { if (nextSleep) { /* Sleep as little as possible. */ wrapperSleep(1); } nextSleep = TRUE; if (wrapperData->pauseThreadJavaIO) { wrapperPauseThread(wrapperData->pauseThreadJavaIO, TEXT("javaio")); wrapperData->pauseThreadJavaIO = 0; } if (wrapperReadChildOutput(0)) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Pause reading child process output to share cycles.")); } nextSleep = FALSE; } } } __except (exceptionFilterFunction(GetExceptionInformation())) { /* This call is not queued to make sure it makes it to the log prior to a shutdown. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Fatal error in the %s thread."), TEXT("JavaIO")); javaIOThreadStopped = TRUE; /* Before appExit() */ appExit(1); return 1; /* For the compiler, we will never get here. */ } javaIOThreadStopped = TRUE; if (wrapperData->isJavaIOOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s thread stopped."), TEXT("JavaIO")); } return 0; } /** * Creates a thread whose job is to loop and process and stdio and stderr * output from the JVM. */ int initializeJavaIO() { if (wrapperData->isJavaIOOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Launching %s thread."), TEXT("JavaIO")); } javaIOThreadHandle = CreateThread( NULL, /* No security attributes as there will not be any child processes of the thread. */ 0, /* Use the default stack size. */ javaIORunner, NULL, /* No parameters need to passed to the thread. */ 0, /* Start the thread running immediately. */ &javaIOThreadId); if (!javaIOThreadHandle) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to create a %s thread: %s"), TEXT("JavaIO"), getLastErrorText()); return 1; } else { return 0; } } void disposeJavaIO() { stopJavaIOThread = TRUE; /* Wait until the javaIO thread is actually stopped to avoid timing problems. */ if (javaIOThreadStarted) { while (!javaIOThreadStopped) { #ifdef _DEBUG wprintf(TEXT("Waiting for %s thread to stop.\n"), TEXT("JavaIO")); #endif wrapperSleep(100); } } } /** * The main entry point for the timer thread which is started by * initializeTimer(). Once started, this thread will run for the * life of the process. * * This thread will only be started if we are configured NOT to * use the system time as a base for the tick counter. */ DWORD WINAPI timerRunner(LPVOID parameter) { TICKS sysTicks; TICKS lastTickOffset = 0; TICKS tickOffset; TICKS nowTicks; int offsetDiff; int first = TRUE; /* In case there are ever any problems in this thread, enclose it in a try catch block. */ __try { timerThreadStarted = TRUE; /* Immediately register this thread with the logger. */ logRegisterThread(WRAPPER_THREAD_TIMER); if (wrapperData->isTickOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Timer thread started.")); } while (!stopTimerThread) { wrapperSleep(WRAPPER_TICK_MS); if (wrapperData->pauseThreadTimer) { wrapperPauseThread(wrapperData->pauseThreadTimer, TEXT("timer")); wrapperData->pauseThreadTimer = 0; } /* Get the tick count based on the system time. */ sysTicks = wrapperGetSystemTicks(); /* Lock the tick mutex whenever the "timerTicks" variable is accessed. */ if (wrapperData->useTickMutex && wrapperLockTickMutex()) { timerThreadStopped = TRUE; return 1; } /* Advance the timer tick count. */ nowTicks = timerTicks++; if (wrapperData->useTickMutex && wrapperReleaseTickMutex()) { timerThreadStopped = TRUE; return 1; } /* Calculate the offset between the two tick counts. This will always work due to overflow. */ tickOffset = sysTicks - nowTicks; /* The number we really want is the difference between this tickOffset and the previous one. */ offsetDiff = wrapperGetTickAgeTicks(lastTickOffset, tickOffset); if (first) { first = FALSE; } else { if (offsetDiff > wrapperData->timerSlowThreshold) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT( "The timer fell behind the system clock by %dms."), (int)(offsetDiff * WRAPPER_TICK_MS)); } else if (offsetDiff < -1 * wrapperData->timerFastThreshold) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT( "The system clock fell behind the timer by %dms."), (int)(-1 * offsetDiff * WRAPPER_TICK_MS)); } if (wrapperData->isTickOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT( " Timer: ticks=%08x, system ticks=%08x, offset=%08x, offsetDiff=%08x"), nowTicks, sysTicks, tickOffset, offsetDiff); } } /* Store this tick offset for the next time through the loop. */ lastTickOffset = tickOffset; } } __except (exceptionFilterFunction(GetExceptionInformation())) { /* This call is not queued to make sure it makes it to the log prior to a shutdown. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Fatal error in the Timer thread.")); timerThreadStopped = TRUE; /* Before appExit() */ appExit(1); return 1; /* For the compiler, we will never get here. */ } timerThreadStopped = TRUE; if (wrapperData->isTickOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Timer thread stopped.")); } return 0; } /** * Creates a process whose job is to loop and simply increment a ticks * counter. The tick counter can then be used as a clock as an alternative * to using the system clock. */ int initializeTimer() { if (wrapperData->isTickOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Launching Timer thread.")); } timerThreadHandle = CreateThread( NULL, /* No security attributes as there will not be any child processes of the thread. */ 0, /* Use the default stack size. */ timerRunner, NULL, /* No parameters need to passed to the thread. */ 0, /* Start the thread running immediately. */ &timerThreadId); if (!timerThreadHandle) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to create a timer thread: %s"), getLastErrorText()); return 1; } else { return 0; } } void disposeTimer() { stopTimerThread = TRUE; /* Wait until the timer thread is actually stopped to avoid timing problems. */ if (timerThreadStarted) { while (!timerThreadStopped) { #ifdef _DEBUG wprintf(TEXT("Waiting for timer thread to stop.\n")); #endif wrapperSleep(100); } } } int initializeWinSock() { WORD ws_version=MAKEWORD(1, 1); WSADATA ws_data; int res; /* Initialize Winsock */ if ((res = WSAStartup(ws_version, &ws_data)) != 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Cannot initialize Windows socket DLLs.")); return res; } return 0; } /** * Collects the current process's username and domain name. * * @return TRUE if there were any problems. */ int collectUserInfo() { int result; DWORD processId; HANDLE hProcess; HANDLE hProcessToken; TOKEN_USER *tokenUser; DWORD tokenUserSize; TCHAR *sidText; DWORD userNameSize; DWORD domainNameSize; SID_NAME_USE sidType; processId = wrapperData->wrapperPID; wrapperData->userName = NULL; wrapperData->domainName = NULL; if (hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processId)) { if (OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken)) { GetTokenInformation(hProcessToken, TokenUser, NULL, 0, &tokenUserSize); tokenUser = (TOKEN_USER *)malloc(tokenUserSize); if (!tokenUser) { outOfMemory(TEXT("CUI"), 1); result = TRUE; } else { if (GetTokenInformation(hProcessToken, TokenUser, tokenUser, tokenUserSize, &tokenUserSize)) { /* Get the text representation of the sid. */ if (ConvertSidToStringSid(tokenUser->User.Sid, &sidText) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to Convert SId to String: %s"), getLastErrorText()); result = TRUE; } else { /* We now have an SID, use it to lookup the account. */ userNameSize = 0; domainNameSize = 0; LookupAccountSid(NULL, tokenUser->User.Sid, NULL, &userNameSize, NULL, &domainNameSize, &sidType); wrapperData->userName = (TCHAR*)malloc(sizeof(TCHAR) * userNameSize); if (!wrapperData->userName) { outOfMemory(TEXT("CUI"), 2); result = TRUE; } else { wrapperData->domainName = (TCHAR*)malloc(sizeof(TCHAR) * domainNameSize); if (!wrapperData->domainName) { outOfMemory(TEXT("CUI"), 3); result = TRUE; } else { if (LookupAccountSid(NULL, tokenUser->User.Sid, wrapperData->userName, &userNameSize, wrapperData->domainName, &domainNameSize, &sidType)) { /* Success. */ result = FALSE; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to get the current username and domain: %s"), getLastErrorText()); result = TRUE; } } } LocalFree(sidText); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to get token information: %s"), getLastErrorText()); result = TRUE; } free(tokenUser); } CloseHandle(hProcessToken); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to open process token: %s"), getLastErrorText()); result = TRUE; } CloseHandle(hProcess); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to open process: %s"), getLastErrorText()); result = TRUE; } return result; } /** * Execute initialization code to get the wrapper set up. */ int wrapperInitializeRun() { HANDLE hStdout; HANDLE hStdErr; HANDLE hStdIn; #ifdef WIN32 struct _timeb timebNow; FILE *pfile; #else struct timeval timevalNow; #endif time_t now; int nowMillis; int res; TCHAR titleBuffer[80]; /* Set the process priority. */ HANDLE process = GetCurrentProcess(); if (!SetPriorityClass(process, wrapperData->ntServicePriorityClass)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to set the process priority: %s"), getLastErrorText()); } /* Initialize the random seed. */ #ifdef WIN32 _ftime(&timebNow); now = (time_t)timebNow.time; nowMillis = timebNow.millitm; #else gettimeofday(&timevalNow, NULL); now = (time_t)timevalNow.tv_sec; nowMillis = timevalNow.tv_usec / 1000; #endif srand(nowMillis); /* Initialize the pipe to capture the child process output */ if ((res = wrapperInitChildPipe()) != 0) { return res; } /* Initialize the Wrapper console handle to null */ wrapperData->wrapperConsoleHWND = NULL; /* The Wrapper will not have its own console when running as a service. We need * to create one here. */ if ((!wrapperData->isConsole) && (wrapperData->ntAllocConsole)) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Allocating a console for the service.")); } if (!AllocConsole()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("ERROR: Unable to allocate a console for the service: %s"), getLastErrorText()); return 1; } /* A console, which got created by AllocConsole, does not have stdin/out/err set, so all printf's are not being displayed. Set the buffer explicitly here. */ hStdIn = GetStdHandle(STD_INPUT_HANDLE); if (hStdIn == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("ERROR: Unable to get the new stdin handle: %s"), getLastErrorText()); return 1; } pfile = _tfdopen( _open_osfhandle((long)hStdIn, _O_TEXT), TEXT("r") ); /* Assign the STD_INPUT_HANDLE fd to stdin*/ *stdin = *pfile; /* set the stream to non buffering */ setvbuf( stdin, NULL, _IONBF, 0 ); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (hStdout == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("ERROR: Unable to get the new stdout handle: %s"), getLastErrorText()); return 1; } pfile = _tfdopen( _open_osfhandle((long)hStdout, _O_TEXT), TEXT("w") ); *stdout = *pfile; setvbuf( stdout, NULL, _IONBF, 0 ); hStdErr = GetStdHandle(STD_ERROR_HANDLE); if (hStdErr == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("ERROR: Unable to get the new stderr handle: %s"), getLastErrorText()); return 1; } pfile = _tfdopen( _open_osfhandle((long)hStdErr, _O_TEXT), TEXT("w") ); *stderr = *pfile; setvbuf( stderr, NULL, _IONBF, 0 ); if (wrapperData->ntHideWrapperConsole) { /* A console needed to be allocated for the process but it should be hidden. */ /* Generate a unique time for the console so we can look for it below. */ _sntprintf(titleBuffer, 80, TEXT("Wrapper Console Id %d-%d (Do not close)"), wrapperData->wrapperPID, rand()); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Wrapper console title: %s"), titleBuffer); #endif SetConsoleTitle(titleBuffer); wrapperData->wrapperConsoleHide = TRUE; if (wrapperData->wrapperConsoleHWND = findConsoleWindow(titleBuffer)) { wrapperData->wrapperConsoleVisible = TRUE; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Found console window.")); } /* Attempt to hide the console window here once so it goes away as quickly as possible. * This may not succeed yet however. If the system is still coming up. */ wrapperCheckConsoleWindows(); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to locate the console window so it can be hidden.")); } } /* If we get here then we created a new console for the Wrapper. If direct console was enabled then we need * to reenable it here as any previous attempted log entries will have reset the direct mode. */ setConsoleDirect(getBooleanProperty(properties, TEXT("wrapper.console.direct"), TRUE)); } /* Attempt to set the console title if it exists and is accessable. */ if (wrapperData->consoleTitle) { if (wrapperData->isConsole || (wrapperData->ntServiceInteractive && !wrapperData->ntHideWrapperConsole)) { /* The console should be visible. */ if (!SetConsoleTitle(wrapperData->consoleTitle)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Attempt to set the console title failed: %s"), getLastErrorText()); } } } /* Set the handler to trap console signals. This must be done after the console * is created or it will not be applied to that console. */ SetConsoleCtrlHandler((PHANDLER_ROUTINE)wrapperConsoleHandler, TRUE); /* Collect the HINSTANCE and HWND references. */ wrapperData->wrapperHInstance = GetModuleHandle(NULL); if (!wrapperData->wrapperConsoleHWND) { wrapperData->wrapperConsoleHWND = GetConsoleWindow(); } if (wrapperData->useSystemTime) { /* We are going to be using system time so there is no reason to start up a timer thread. */ timerThreadHandle = NULL; timerThreadId = 0; } else { /* Create and initialize a timer thread. */ if ((res = initializeTimer()) != 0) { return res; } } if (wrapperData->useJavaIOThread) { /* Create and initialize a javaIO thread. */ if ((res = initializeJavaIO()) != 0) { return res; } } else { javaIOThreadHandle = NULL; javaIOThreadId = 0; } if (wrapperData->isPageFaultOutputEnabled) { wrapperInitializeProfileCounters(); } return 0; } /** * Cause the current thread to sleep for the specified number of milliseconds. * Sleeps over one second are not allowed. * * @param ms Number of milliseconds to wait for. * * @return TRUE if the was interrupted, FALSE otherwise. Neither is an error. */ int wrapperSleep(int ms) { if (wrapperData->isSleepOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Sleep: sleep %dms"), ms); } Sleep(ms); if (wrapperData->isSleepOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Sleep: awake")); } return FALSE; } /** * Detaches the Java process so the Wrapper will if effect forget about it. */ void wrapperDetachJava() { wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, 0, -1); } /** * Reports the status of the wrapper to the service manager * Possible status values: * WRAPPER_WSTATE_STARTING * WRAPPER_WSTATE_STARTED * WRAPPER_WSTATE_PAUSING * WRAPPER_WSTATE_PAUSED * WRAPPER_WSTATE_RESUMING * WRAPPER_WSTATE_STOPPING * WRAPPER_WSTATE_STOPPED */ void wrapperReportStatus(int useLoggerQueue, int status, int errorCode, int waitHint) { int natState; TCHAR *natStateName; static DWORD dwCheckPoint = 1; BOOL bResult = TRUE; /* log_printf_queue(useLoggerQueue, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, "wrapperReportStatus(%d, %d, %d, %d)", useLoggerQueue, status, errorCode, waitHint); */ switch (status) { case WRAPPER_WSTATE_STARTING: natState = SERVICE_START_PENDING; natStateName = TEXT("SERVICE_START_PENDING"); break; case WRAPPER_WSTATE_STARTED: natState = SERVICE_RUNNING; natStateName = TEXT("SERVICE_RUNNING"); break; case WRAPPER_WSTATE_PAUSING: natState = SERVICE_PAUSE_PENDING; natStateName = TEXT("SERVICE_PAUSE_PENDING"); break; case WRAPPER_WSTATE_PAUSED: natState = SERVICE_PAUSED; natStateName = TEXT("SERVICE_PAUSED"); break; case WRAPPER_WSTATE_RESUMING: natState = SERVICE_CONTINUE_PENDING; natStateName = TEXT("SERVICE_CONTINUE_PENDING"); break; case WRAPPER_WSTATE_STOPPING: natState = SERVICE_STOP_PENDING; natStateName = TEXT("SERVICE_STOP_PENDING"); break; case WRAPPER_WSTATE_STOPPED: natState = SERVICE_STOPPED; natStateName = TEXT("SERVICE_STOPPED"); break; default: log_printf_queue(useLoggerQueue, WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unknown status: %d"), status); return; } if (!wrapperData->isConsole) { ssStatus.dwControlsAccepted = 0; if (natState != SERVICE_START_PENDING) { ssStatus.dwControlsAccepted |= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; if (wrapperData->pausable) { ssStatus.dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; } } if (isWindowsNT4_0OrEarlier()) { /* Old Windows - Does not support power events. */ } else { /* Supports power events. */ ssStatus.dwControlsAccepted |= SERVICE_ACCEPT_POWEREVENT; } /* if (wrapperData->isDebugging) { log_printf_queue(useLoggerQueue, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, " Service %s accepting STOP=%s, SHUTDOWN=%s, PAUSE/CONTINUE=%s, POWEREVENT=%s", natStateName, (ssStatus.dwControlsAccepted & SERVICE_ACCEPT_STOP ? "True" : "False"), (ssStatus.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN ? "True" : "False"), (ssStatus.dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE ? "True" : "False"), (ssStatus.dwControlsAccepted & SERVICE_ACCEPT_POWEREVENT ? "True" : "False")); } */ ssStatus.dwCurrentState = natState; if (errorCode == 0) { ssStatus.dwWin32ExitCode = NO_ERROR; ssStatus.dwServiceSpecificExitCode = 0; } else { ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; ssStatus.dwServiceSpecificExitCode = errorCode; } ssStatus.dwWaitHint = waitHint; if ((natState == SERVICE_RUNNING) || (natState == SERVICE_STOPPED) || (natState == SERVICE_PAUSED)) { ssStatus.dwCheckPoint = 0; } else { ssStatus.dwCheckPoint = dwCheckPoint++; } if (wrapperData->isStateOutputEnabled) { log_printf_queue(useLoggerQueue, WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("calling SetServiceStatus with status=%s, waitHint=%d, checkPoint=%u, errorCode=%d"), natStateName, waitHint, dwCheckPoint, errorCode); } if (!(bResult = SetServiceStatus(sshStatusHandle, &ssStatus))) { log_printf_queue(useLoggerQueue, WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("SetServiceStatus failed")); } } } /** * Reads a single block of data from the child pipe. * * @param blockBuffer Pointer to the buffer where the block will be read. * @param blockSize Maximum number of bytes to read. * @param readCount Pointer to an int which will hold the number of bytes * actually read by the call. * * Returns TRUE if there were any problems, FALSE otherwise. */ int wrapperReadChildOutputBlock(char *blockBuffer, int blockSize, int *readCount) { DWORD currentBlockAvail; /* See how many characters are available in the pipe so we can say how much to read. */ if (!PeekNamedPipe(wrapperChildStdoutRd, NULL, 0, NULL, ¤tBlockAvail, NULL)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to peek at output from the JVM: %s"), getLastErrorText()); return TRUE; } #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Peeked %d chars from pipe."), currentBlockAvail); #endif if (currentBlockAvail > 0) { /* Attempt to read in an additional CHILD_BLOCK_SIZE characters. */ if (!ReadFile(wrapperChildStdoutRd, blockBuffer, blockSize, readCount, NULL)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to read output from the JVM: %s"), getLastErrorText()); return TRUE; } #ifdef DEBUG_CHILD_OUTPUT log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Read %d chars from pipe."), *readCount); #endif } else { *readCount = 0; } return FALSE; } /** * Checks on the status of the JVM Process. * Returns WRAPPER_PROCESS_UP or WRAPPER_PROCESS_DOWN */ int wrapperGetProcessStatus(TICKS nowTicks, int sigChild) { int res; DWORD exitCode; TCHAR *exName; switch (WaitForSingleObject(wrapperData->javaProcess, 0)) { case WAIT_ABANDONED: case WAIT_OBJECT_0: res = WRAPPER_PROCESS_DOWN; /* Get the exit code of the process. */ if (!GetExitCodeProcess(wrapperData->javaProcess, &exitCode)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Critical error: unable to obtain the exit code of the JVM process: %s"), getLastErrorText()); appExit(1); } if (exitCode == STILL_ACTIVE) { /* Should never happen, but check for it. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The JVM returned JVM exit code was STILL_ACTIVE.") ); } /* If the JVM crashed then GetExitCodeProcess could have returned an uncaught exception. */ exName = getExceptionName(exitCode); if (exName != NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The JVM process terminated due to an uncaught exception: %s (0x%08x)"), exName, exitCode); /* Reset the exit code as the exeption value will confuse users. */ exitCode = 1; } wrapperJVMProcessExited(nowTicks, exitCode); break; case WAIT_TIMEOUT: res = WRAPPER_PROCESS_UP; break; default: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Critical error: wait for JVM process failed: %s"), getLastErrorText()); appExit(1); break; } return res; } /** * Launches a JVM process and store it internally * * @return TRUE if there were any problems. When this happens the Wrapper will not try to restart. */ int wrapperExecute() { SECURITY_ATTRIBUTES process_attributes; STARTUPINFO startup_info; PROCESS_INFORMATION process_info; int ret; /* Do not show another console for the new process */ /*int processflags=CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS; */ /* Create a new process group as part of this console so that signals can */ /* be sent to the JVM. */ DWORD processflags=CREATE_NEW_PROCESS_GROUP; /* Do not show another console for the new process, but show its output in the current console. */ /*int processflags=CREATE_NEW_PROCESS_GROUP; */ /* Show a console for the new process */ /*int processflags=CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE; */ size_t len; TCHAR *environment=NULL; TCHAR *binparam=NULL; int char_block_size = 8196; int string_size = 0; int temp_int = 0; TCHAR szPath[_MAX_PATH]; DWORD usedLen; TCHAR *c; TCHAR titleBuffer[80]; int hideConsole; int old_umask; FILE *pid_fp = NULL; /* Reset the exit code when we launch a new JVM. */ wrapperData->exitCode = 0; /* Add the priority class of the new process to the processflags */ processflags = processflags | wrapperData->ntServicePriorityClass; /* Update the CLASSPATH in the environment if requested so the JVM can access it. */ if (wrapperData->environmentClasspath) { if (setEnv(TEXT("CLASSPATH"), wrapperData->classpath, ENV_SOURCE_APPLICATION)) { /* This can happen if the classpath is too long on Windows. */ wrapperData->javaProcess = NULL; return TRUE; } } /* Make sure the classpath is not too long. */ len = _tcslen(wrapperData->jvmCommand); if (len > MAX_COMMAND_LINE_LEN) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("The generated Java command line has a length of %d, which is longer than the Windows maximum of %d characters."), len, MAX_COMMAND_LINE_LEN); if (!wrapperData->environmentClasspath) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" You may be able to shorten your command line by setting wrapper.java.classpath.use_environment.")); } wrapperData->javaProcess = NULL; return TRUE; } /* Log the Java commands. */ /* If the JVM version printout is requested then log its command line first. */ if (wrapperData->printJVMVersion) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Java Command Line (Query Java Version):")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" Command: %s"), wrapperData->jvmVersionCommand); } } /* Log ghe application java command line */ if (wrapperData->commandLogLevel != LEVEL_NONE) { log_printf(WRAPPER_SOURCE_WRAPPER, wrapperData->commandLogLevel, TEXT("Java Command Line:")); log_printf(WRAPPER_SOURCE_WRAPPER, wrapperData->commandLogLevel, TEXT(" Command: %s"), wrapperData->jvmCommand); if (wrapperData->environmentClasspath) { log_printf(WRAPPER_SOURCE_WRAPPER, wrapperData->commandLogLevel, TEXT(" Classpath in Environment : %s"), wrapperData->classpath); } } /* Setup environment. Use parent's for now */ environment = NULL; /* Initialize a SECURITY_ATTRIBUTES for the process attributes of the new process. */ process_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); process_attributes.lpSecurityDescriptor = NULL; process_attributes.bInheritHandle = TRUE; /* Generate a unique time for the console so we can look for it below. */ _sntprintf(titleBuffer, 80, TEXT("Wrapper Controlled JVM Console Id %d-%d (Do not close)"), wrapperData->wrapperPID, rand()); /* Initialize a STARTUPINFO structure to use for the new process. */ startup_info.cb=sizeof(STARTUPINFO); startup_info.lpReserved=NULL; startup_info.lpDesktop=NULL; startup_info.lpTitle=titleBuffer; startup_info.dwX=0; startup_info.dwY=0; startup_info.dwXSize=0; startup_info.dwYSize=0; startup_info.dwXCountChars=0; startup_info.dwYCountChars=0; startup_info.dwFillAttribute=0; /* Set the default flags which will not hide any windows opened by the JVM. */ /* Using Show Window and SW_HIDE seems to make it impossible to show any windows when the 32-bit version runs as a service. startup_info.dwFlags=STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; startup_info.wShowWindow=SW_HIDE; */ startup_info.dwFlags=STARTF_USESTDHANDLES; startup_info.wShowWindow=0; hideConsole = FALSE; if (wrapperData->isConsole) { /* We are running as a console so no special console handling needs to be done. */ } else { /* Running as a service. */ if (wrapperData->ntAllocConsole) { /* A console was allocated when the service was started so the JVM will not create * its own. */ if ((wrapperData->wrapperConsoleHWND) && (wrapperData->wrapperConsoleHide)) { /* The console exists but is currently hidden. */ if (!wrapperData->ntHideJVMConsole) { /* In order to support older JVMs we need to show the console when the * JVM is launched. We need to remember to hide it below. */ showConsoleWindow(wrapperData->wrapperConsoleHWND, TEXT("Wrapper")); wrapperData->wrapperConsoleVisible = TRUE; wrapperData->wrapperConsoleHide = FALSE; /* Temporarily disable the hide flag so the event loop won't hide it while we are launching the JVM. */ hideConsole = TRUE; } } } else { /* A console does not yet exist so the JVM will create and display one itself. */ if (wrapperData->ntHideJVMConsole) { /* The console that the JVM creates should be surpressed and never shown. * JVMs of version 1.4.0 and above will still display a GUI. But older JVMs * will not. */ startup_info.dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; startup_info.wShowWindow=SW_HIDE; } else { /* The new JVM console should be allowed to be displayed. But we need to * remember to hide it below. */ hideConsole = TRUE; } } } startup_info.cbReserved2 = 0; startup_info.lpReserved2 = NULL; startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); startup_info.hStdOutput = wrapperChildStdoutWr; startup_info.hStdError = wrapperChildStdoutWr; /* Initialize a PROCESS_INFORMATION structure to use for the new process */ process_info.hProcess = NULL; process_info.hThread = NULL; process_info.dwProcessId = 0; process_info.dwThreadId = 0; /* Need the directory that this program exists in. Not the current directory. */ /* Note, the current directory when run as an NT service is the windows system directory. */ /* Get the full path and filename of this program */ usedLen = GetModuleFileName(NULL, szPath, _MAX_PATH); if (usedLen == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to launch %s -%s"), wrapperData->serviceDisplayName, getLastErrorText()); wrapperData->javaProcess = NULL; return TRUE; } else if ((usedLen == _MAX_PATH) || (getLastError() == ERROR_INSUFFICIENT_BUFFER)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to launch %s -%s"), wrapperData->serviceDisplayName, TEXT("Path to Wrapper binary too long.")); wrapperData->javaProcess = NULL; return TRUE; } c = _tcsrchr(szPath, TEXT('\\')); if (c == NULL) { szPath[0] = TEXT('\0'); } else { c[1] = TEXT('\0'); /* terminate after the slash */ } /* Make sure the log file is closed before the Java process is created. Failure to do * so will give the Java process a copy of the open file. This means that this process * will not be able to rename the file even after closing it because it will still be * open in the Java process. Also set the auto close flag to make sure that other * threads do not reopen the log file as the new process is being created. */ setLogfileAutoClose(TRUE); closeLogfile(); /* Reset the log duration so we get new counts from the time the JVM is launched. */ resetDuration(); /* Set the umask of the JVM */ old_umask = _umask(wrapperData->javaUmask); /* If set, this will launch a second JVM before the actual one to quickly print out the JVM version information. * This will appear to come from the same JVM instance in the logs. */ if (wrapperData->printJVMVersion) { if (CreateProcess(NULL, wrapperData->jvmVersionCommand, /* the command line to start */ NULL, /* process security attributes */ NULL, /* primary thread security attributes */ TRUE, /* handles are inherited */ processflags, /* we specify new process group */ environment, /* use parent's environment */ NULL, /* use the Wrapper's current working directory */ &startup_info, /* STARTUPINFO pointer */ &process_info /* PROCESS_INFORMATION pointer */ ) != 0) { /* Always wait for the process to complate. We don't currently do anything fancy here as the -version request will always exit immediately. */ WaitForSingleObject(process_info.hProcess, INFINITE); CloseHandle(process_info.hProcess); CloseHandle(process_info.hThread); } } /* Create the new process */ ret=CreateProcess(NULL, wrapperData->jvmCommand, /* the command line to start */ NULL, /* process security attributes */ NULL, /* primary thread security attributes */ TRUE, /* handles are inherited */ processflags, /* we specify new process group */ environment, /* use parent's environment */ NULL, /* use the Wrapper's current working directory */ &startup_info, /* STARTUPINFO pointer */ &process_info); /* PROCESS_INFORMATION pointer */ /* Restore the umask. */ _umask(old_umask); /* As soon as the new process is created, restore the auto close flag. */ setLogfileAutoClose(wrapperData->logfileCloseTimeout == 0); /* Check if virtual machine started */ if (ret==FALSE) { int err=GetLastError(); /* Make sure the process was launched correctly. */ if (err!=NO_ERROR) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to execute Java command. %s"), getLastErrorText()); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" %s"), wrapperData->jvmCommand); wrapperData->javaProcess = NULL; if ((err == ERROR_FILE_NOT_FOUND) || (err == ERROR_PATH_NOT_FOUND)) { if (wrapperData->isAdviserEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Advice:" )); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Usually when the Wrapper fails to start the JVM process, it is\nbecause of a problem with the value of the configured Java command.\nCurrently:" )); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("wrapper.java.command=%s"), getStringProperty(properties, TEXT("wrapper.java.command"), TEXT("java"))); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Please make sure that the PATH or any other referenced environment\nvariables are correctly defined for the current environment." )); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); } } else if (err == ERROR_ACCESS_DENIED) { if (wrapperData->isAdviserEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT( "Advice:" )); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT( "Access denied errors when attempting to launch the Java process are\nusually caused by strict access permissions assigned to the\ndirectory in which Java is installed." )); if (!wrapperData->isConsole) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT( "Unless you have configured the Wrapper to run as a different user\nwith wrapper.ntservice.account property, the Wrapper and its JVM\nwill be as the SYSTEM user by default when run as a service." )); } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); } } /* This is always a permanent problem. */ return TRUE; } } /* Now check if we have a process handle again for the Swedish WinNT bug */ if (process_info.hProcess == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("can not execute \"%s\""), wrapperData->jvmCommand); wrapperData->javaProcess = NULL; return TRUE; } if (hideConsole) { /* Now that the JVM has been launched we need to hide the console that it * is using. */ if (wrapperData->wrapperConsoleHWND) { /* The wrapper's console needs to be hidden. */ wrapperData->wrapperConsoleHide = TRUE; wrapperCheckConsoleWindows(); } else { /* We need to locate the console that was created by the JVM on launch * and hide it. */ wrapperData->jvmConsoleHandle = findConsoleWindow(titleBuffer); wrapperData->jvmConsoleVisible = TRUE; /* This will be cleared if the check call successfully hides it. */ wrapperCheckConsoleWindows(); } } if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM started (PID=%d)"), process_info.dwProcessId); } /* We keep a reference to the process handle, but need to close the thread handle. */ wrapperData->javaProcess = process_info.hProcess; wrapperData->javaPID = process_info.dwProcessId; CloseHandle(process_info.hThread); /* If a java pid filename is specified then write the pid of the java process. */ if (wrapperData->javaPidFilename) { if (writePidFile(wrapperData->javaPidFilename, wrapperData->javaPID, wrapperData->javaPidFileUmask, FALSE)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to write the Java PID file: %s"), wrapperData->javaPidFilename); } } /* If a java id filename is specified then write the id of the java process. */ if (wrapperData->javaIdFilename) { if (writePidFile(wrapperData->javaIdFilename, wrapperData->jvmRestarts, wrapperData->javaIdFileUmask, FALSE)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to write the Java Id file: %s"), wrapperData->javaIdFilename); } } return FALSE; } /** * Returns a tick count that can be used in combination with the * wrapperGetTickAgeSeconds() function to perform time keeping. */ TICKS wrapperGetTicks() { TICKS ticks; if (wrapperData->useSystemTime) { /* We want to return a tick count that is based on the current system time. */ ticks = wrapperGetSystemTicks(); } else { /* Lock the tick mutex whenever the "timerTicks" variable is accessed. */ if (wrapperData->useTickMutex && wrapperLockTickMutex()) { return 0; } /* Return a snapshot of the current tick count. */ ticks = timerTicks; if (wrapperData->useTickMutex && wrapperReleaseTickMutex()) { return 0; } } return ticks; } /** * Outputs a a log entry describing what the memory dump columns are. */ void wrapperDumpMemoryBanner() { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper memory: PageFaultcount, WorkingSetSize (Peak), QuotaPagePoolUsage (Peak), QuotaNonPagedPoolUsage (Peak), PageFileUsage (Peak) Java memory: PageFaultcount, WorkingSetSize (Peak), QuotaPagePoolUsage (Peak), QuotaNonPagedPoolUsage (Peak), PageFileUsage (Peak) System memory: MemoryLoad, Available/PhysicalSize (%%), Available/PageFileSize (%%), Available/VirtualSize (%%), ExtendedVirtualSize")); } /** * Outputs a log entry at regular intervals to track the memory usage of the * Wrapper and its JVM. */ void wrapperDumpMemory() { PROCESS_MEMORY_COUNTERS wCounters; PROCESS_MEMORY_COUNTERS jCounters; MEMORYSTATUSEX statex; if (OptionalGetProcessMemoryInfo) { /* Start with the Wrapper process. */ if (OptionalGetProcessMemoryInfo(wrapperData->wrapperProcess, &wCounters, sizeof(wCounters)) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Call to GetProcessMemoryInfo failed for Wrapper process %08x: %s"), wrapperData->wrapperPID, getLastErrorText()); return; } if (wrapperData->javaProcess != NULL) { /* Next the Java process. */ if (OptionalGetProcessMemoryInfo(wrapperData->javaProcess, &jCounters, sizeof(jCounters)) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Call to GetProcessMemoryInfo failed for Java process %08x: %s"), wrapperData->javaPID, getLastErrorText()); return; } } else { memset(&jCounters, 0, sizeof(jCounters)); } statex.dwLength = sizeof(statex); GlobalMemoryStatusEx(&statex); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper memory: %lu, %lu (%lu), %lu (%lu), %lu (%lu), %lu (%lu) Java memory: %lu, %lu (%lu), %lu (%lu), %lu (%lu), %lu (%lu) System memory: %lu%%, %I64u/%I64u (%u%%), %I64u/%I64u (%u%%), %I64u/%I64u (%u%%), %I64u"), wCounters.PageFaultCount, wCounters.WorkingSetSize, wCounters.PeakWorkingSetSize, wCounters.QuotaPagedPoolUsage, wCounters.QuotaPeakPagedPoolUsage, wCounters.QuotaNonPagedPoolUsage, wCounters.QuotaPeakNonPagedPoolUsage, wCounters.PagefileUsage, wCounters.PeakPagefileUsage, jCounters.PageFaultCount, jCounters.WorkingSetSize, jCounters.PeakWorkingSetSize, jCounters.QuotaPagedPoolUsage, jCounters.QuotaPeakPagedPoolUsage, jCounters.QuotaNonPagedPoolUsage, jCounters.QuotaPeakNonPagedPoolUsage, jCounters.PagefileUsage, jCounters.PeakPagefileUsage, statex.dwMemoryLoad, statex.ullAvailPhys, statex.ullTotalPhys, (int)(100 * statex.ullAvailPhys / statex.ullTotalPhys), statex.ullAvailPageFile, statex.ullTotalPageFile, (int)(100 * statex.ullAvailPageFile / statex.ullTotalPageFile), statex.ullAvailVirtual, statex.ullTotalVirtual, (int)(100 * statex.ullAvailVirtual / statex.ullTotalVirtual), statex.ullAvailExtendedVirtual); } } DWORD filetimeToMS(FILETIME* filetime) { LARGE_INTEGER li; memcpy(&li, filetime, sizeof(li)); li.QuadPart /= 10000; return li.LowPart; } /** * Outputs a log entry at regular intervals to track the CPU usage over each * interval for the Wrapper and its JVM. * * In order to make sense of the timing values, it is also necessary to see how * far the system performance counter has progressed. By carefully comparing * these values, it is possible to very accurately calculate the CPU usage over * any period of time. */ LONGLONG lastPerformanceCount = 0; LONGLONG lastWrapperKernelTime = 0; LONGLONG lastWrapperUserTime = 0; LONGLONG lastJavaKernelTime = 0; LONGLONG lastJavaUserTime = 0; LONGLONG lastIdleKernelTime = 0; LONGLONG lastIdleUserTime = 0; void wrapperDumpCPUUsage() { LARGE_INTEGER count; LARGE_INTEGER frequency; LARGE_INTEGER li; LONGLONG performanceCount; FILETIME creationTime; FILETIME exitTime; FILETIME wKernelTime; FILETIME wUserTime; FILETIME jKernelTime; FILETIME jUserTime; DWORD wKernelTimeMs; /* Will overflow in 49 days of usage. */ DWORD wUserTimeMs; DWORD wTimeMs; DWORD jKernelTimeMs; DWORD jUserTimeMs; DWORD jTimeMs; double age; double wKernelPercent; double wUserPercent; double wPercent; double jKernelPercent; double jUserPercent; double jPercent; if (OptionalGetProcessTimes) { if (!QueryPerformanceCounter(&count)) { /* no high-resolution performance counter support. */ return; } if (!QueryPerformanceFrequency(&frequency)) { } performanceCount = count.QuadPart; /* Start with the Wrapper process. */ if (!OptionalGetProcessTimes(wrapperData->wrapperProcess, &creationTime, &exitTime, &wKernelTime, &wUserTime)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Call to GetProcessTimes failed for Wrapper process %08x: %s"), wrapperData->wrapperPID, getLastErrorText()); return; } if (wrapperData->javaProcess != NULL) { /* Next the Java process. */ if (!OptionalGetProcessTimes(wrapperData->javaProcess, &creationTime, &exitTime, &jKernelTime, &jUserTime)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Call to GetProcessTimes failed for Java process %08x: %s"), wrapperData->javaPID, getLastErrorText()); return; } } else { memset(&jKernelTime, 0, sizeof(jKernelTime)); memset(&jUserTime, 0, sizeof(jUserTime)); lastJavaKernelTime = 0; lastJavaUserTime = 0; } /* Convert the times to ms. */ wKernelTimeMs = filetimeToMS(&wKernelTime); wUserTimeMs = filetimeToMS(&wUserTime); wTimeMs = wKernelTimeMs + wUserTimeMs; jKernelTimeMs = filetimeToMS(&jKernelTime); jUserTimeMs = filetimeToMS(&jUserTime); jTimeMs = jKernelTimeMs + jUserTimeMs; /* Calculate the number of seconds since the last call. */ age = (double)(performanceCount - lastPerformanceCount) / frequency.QuadPart; /* Calculate usage percentages. */ memcpy(&li, &wKernelTime, sizeof(li)); wKernelPercent = 100.0 * ((li.QuadPart - lastWrapperKernelTime) / 10000000.0) / age; lastWrapperKernelTime = li.QuadPart; memcpy(&li, &wUserTime, sizeof(li)); wUserPercent = 100.0 * ((li.QuadPart - lastWrapperUserTime) / 10000000.0) / age; lastWrapperUserTime = li.QuadPart; wPercent = wKernelPercent + wUserPercent; memcpy(&li, &jKernelTime, sizeof(li)); jKernelPercent = 100.0 * ((li.QuadPart - lastJavaKernelTime) / 10000000.0) / age; lastJavaKernelTime = li.QuadPart; memcpy(&li, &jUserTime, sizeof(li)); jUserPercent = 100.0 * ((li.QuadPart - lastJavaUserTime) / 10000000.0) / age; lastJavaUserTime = li.QuadPart; jPercent = jKernelPercent + jUserPercent; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper CPU: kernel %ldms (%5.2f%%), user %ldms (%5.2f%%), total %ldms (%5.2f%%) Java CPU: kernel %ldms (%5.2f%%), user %ldms (%5.2f%%), total %ldms (%5.2f%%)"), wKernelTimeMs, wKernelPercent, wUserTimeMs, wUserPercent, wTimeMs, wPercent, jKernelTimeMs, jKernelPercent, jUserTimeMs, jUserPercent, jTimeMs, jPercent); lastPerformanceCount = performanceCount; } } void wrapperInitializeProfileCounters() { PDH_STATUS pdhStatus; FARPROC pdhAddUnlocalizedCounter; BOOL couldLoad; HMODULE dbgHelpDll = GetModuleHandle(TEXT("Pdh.dll")); if( dbgHelpDll == NULL) { couldLoad = FALSE; } else { if (isVista()) { #ifdef UNICODE pdhAddUnlocalizedCounter = GetProcAddress(dbgHelpDll, "PdhAddEnglishCounterW"); #else pdhAddUnlocalizedCounter = GetProcAddress(dbgHelpDll, "PdhAddEnglishCounterA"); #endif } else { #ifdef UNICODE pdhAddUnlocalizedCounter = GetProcAddress(dbgHelpDll, "PdhAddCounterW"); #else pdhAddUnlocalizedCounter = GetProcAddress(dbgHelpDll, "PdhAddCounterA"); #endif } if(pdhAddUnlocalizedCounter == NULL) { couldLoad = FALSE; } else { couldLoad = TRUE; } } /* We want to set up system profile monitoring to keep track of the state of the system. */ pdhStatus = PdhOpenQuery(NULL, 0, &pdhQuery); if (pdhStatus != ERROR_SUCCESS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to initialize profiling: 0x%x"), pdhStatus); pdhQuery = NULL; } else { pdhStatus = (PDH_STATUS)pdhAddUnlocalizedCounter(pdhQuery, TEXT("\\PhysicalDisk(_Total)\\Avg. Disk Queue Length"), 0, &pdhCounterPhysicalDiskAvgQueueLen); if (pdhStatus != ERROR_SUCCESS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to initialize profiling counter %d: 0x%x"), 1, pdhStatus); } pdhStatus = (PDH_STATUS)pdhAddUnlocalizedCounter(pdhQuery, TEXT("\\PhysicalDisk(_Total)\\Avg. Disk Write Queue Length"), 0, &pdhCounterPhysicalDiskAvgWriteQueueLen); if (pdhStatus != ERROR_SUCCESS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to initialize profiling counter %d: 0x%x"), 2, pdhStatus); } pdhStatus = (PDH_STATUS)pdhAddUnlocalizedCounter(pdhQuery, TEXT("\\PhysicalDisk(_Total)\\Avg. Disk Read Queue Length"), 0, &pdhCounterPhysicalDiskAvgReadQueueLen); if (pdhStatus != ERROR_SUCCESS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to initialize profiling counter %d: 0x%x"), 3, pdhStatus); } pdhStatus = (PDH_STATUS)pdhAddUnlocalizedCounter(pdhQuery, TEXT("\\Memory\\Page Faults/sec"), 0, &pdhCounterMemoryPageFaultsPSec); if (pdhStatus != ERROR_SUCCESS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to initialize profiling counter %d: 0x%x"), 4, pdhStatus); } pdhStatus = (PDH_STATUS)pdhAddUnlocalizedCounter(pdhQuery, TEXT("\\Memory\\Transition Faults/sec"), 0, &pdhCounterMemoryTransitionFaultsPSec); if (pdhStatus != ERROR_SUCCESS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to initialize profiling counter %d: 0x%x"), 5, pdhStatus); } pdhStatus = (PDH_STATUS)pdhAddUnlocalizedCounter(pdhQuery, TEXT("\\Process(wrapper)\\Page Faults/sec"), 0, &pdhCounterProcessWrapperPageFaultsPSec); if (pdhStatus != ERROR_SUCCESS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to initialize profiling counter %d: 0x%x"), 6, pdhStatus); } pdhStatus = (PDH_STATUS)pdhAddUnlocalizedCounter(pdhQuery, TEXT("\\Process(java)\\Page Faults/sec"), 0, &pdhCounterProcessJavaPageFaultsPSec); if (pdhStatus != ERROR_SUCCESS) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to initialize profiling counter %d: 0x%x"), 7, pdhStatus); } if (couldLoad && dbgHelpDll != NULL) { FreeLibrary(dbgHelpDll); } /* This is the first call, since for some equations (e.g. for average) 2 values need to be polled */ PdhCollectQueryData(pdhQuery); /* PdhGetCounterInfo to get info about the counters like scale, etc. */ } } void wrapperDumpPageFaultUsage() { PDH_STATUS pdhStatus; DWORD counterType; PDH_FMT_COUNTERVALUE counterValue; double diskQueueLen = 0; double diskQueueWLen = 0; double diskQueueRLen = 0; double pageFaults = 0; double transitionPageFaults = 0; double wrapperPageFaults = 0; double javaPageFaults = 0; if (pdhQuery == NULL) { return; } pdhStatus = PdhCollectQueryData(pdhQuery); if (pdhStatus == ERROR_SUCCESS) { pdhStatus = PdhGetFormattedCounterValue(pdhCounterPhysicalDiskAvgQueueLen, PDH_FMT_DOUBLE, &counterType, &counterValue); if (pdhStatus == ERROR_SUCCESS) { diskQueueLen = counterValue.doubleValue; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("\\PhysicalDisk(_Total)\\Avg. Disk Queue Length : %d %10.5f"), counterValue.CStatus, counterValue.doubleValue);*/ } pdhStatus = PdhGetFormattedCounterValue(pdhCounterPhysicalDiskAvgWriteQueueLen, PDH_FMT_DOUBLE, &counterType, &counterValue); if (pdhStatus == ERROR_SUCCESS) { diskQueueWLen = counterValue.doubleValue; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("\\PhysicalDisk(_Total)\\Avg. Disk Write Queue Length : %d %10.5f"), counterValue.CStatus, counterValue.doubleValue);*/ } pdhStatus = PdhGetFormattedCounterValue(pdhCounterPhysicalDiskAvgReadQueueLen, PDH_FMT_DOUBLE, &counterType, &counterValue); if (pdhStatus == ERROR_SUCCESS) { diskQueueRLen = counterValue.doubleValue; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("\\PhysicalDisk(_Total)\\Avg. Disk Read Queue Length : %d %10.5f"), counterValue.CStatus, counterValue.doubleValue);*/ } pdhStatus = PdhGetFormattedCounterValue(pdhCounterMemoryPageFaultsPSec, PDH_FMT_DOUBLE, &counterType, &counterValue); if (pdhStatus == ERROR_SUCCESS) { pageFaults = counterValue.doubleValue; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("\\Memory\\Page Faults/sec : %d %10.5f"), counterValue.CStatus, counterValue.doubleValue);*/ } pdhStatus = PdhGetFormattedCounterValue(pdhCounterMemoryTransitionFaultsPSec, PDH_FMT_DOUBLE, &counterType, &counterValue); if (pdhStatus == ERROR_SUCCESS) { transitionPageFaults = counterValue.doubleValue; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("\\Memory\\Transition Faults/sec : %d %10.5f"), counterValue.CStatus, counterValue.doubleValue);*/ } pdhStatus = PdhGetFormattedCounterValue(pdhCounterProcessWrapperPageFaultsPSec, PDH_FMT_DOUBLE, &counterType, &counterValue); if (pdhStatus == ERROR_SUCCESS) { wrapperPageFaults = counterValue.doubleValue; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("\\Process(wrapper)\\Page Faults/sec : %d %10.5f"), counterValue.CStatus, counterValue.doubleValue);*/ } pdhStatus = PdhGetFormattedCounterValue(pdhCounterProcessJavaPageFaultsPSec, PDH_FMT_DOUBLE, &counterType, &counterValue); if (pdhStatus == ERROR_SUCCESS) { javaPageFaults = counterValue.doubleValue; /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("\\Process(java)\\Page Faults/sec : %d %10.5f"), counterValue.CStatus, counterValue.doubleValue);*/ } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Page Faults (Total:%8.2f%8.2f:%8.2f Wrapper:%7.2f (%7.2f%%) Java:%7.2f (%7.2f%%)) Queue Len (Total:%7.2f Read:%7.2f Write:%7.2f)"), pageFaults, transitionPageFaults, pageFaults - transitionPageFaults, wrapperPageFaults, (pageFaults > 0 ? 100 * wrapperPageFaults / pageFaults : 0), javaPageFaults, (pageFaults > 0 ? 100 * javaPageFaults / pageFaults : 0), diskQueueLen, diskQueueRLen, diskQueueWLen); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Failed to collect profile data: 0x%x"), pdhStatus); } } void disposeProfileCounters() { if (pdhQuery != NULL) { PdhCloseQuery(pdhQuery); pdhQuery = NULL; } } /****************************************************************************** * NT Service Methods *****************************************************************************/ /** * This function goes through and checks flags for each of several signals to see if they * have been fired since the last time this function was called. This is the only thread * which will ever clear these flags, but they can be set by other threads within the * signal handlers at ANY time. So only check the value of each flag once and reset them * immediately to decrease the chance of missing duplicate signals. */ void wrapperMaintainControlCodes() { /* Allow for a large integer + \0 */ TCHAR buffer[11]; int ctrlCodeLast; int quit = FALSE; int halt = FALSE; /* CTRL_C_EVENT */ if (wrapperData->ctrlEventCTRLCTrapped) { wrapperData->ctrlEventCTRLCTrapped = FALSE; /* Always quit. If the user has pressed CTRL-C previously then we want to force * an immediate shutdown. */ if (ctrlCTrapped) { /* Pressed CTRL-C more than once. */ if (wrapperData->isForcedShutdownDisabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Already shutting down."), TEXT("CTRL-C")); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Forcing immediate shutdown."), TEXT("CTRL-C")); halt = TRUE; } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Shutting down."), TEXT("CTRL-C")); ctrlCTrapped = TRUE; } quit = TRUE; } /* CTRL_CLOSE_EVENT */ if (wrapperData->ctrlEventCloseTrapped) { wrapperData->ctrlEventCloseTrapped = FALSE; /* Always quit. If the user has tried to close the console previously then we want to force * an immediate shutdown. */ if (ctrlCTrapped) { /* Pressed Close or CTRL-C more than once. */ if (wrapperData->isForcedShutdownDisabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Already shutting down."), TEXT("Close")); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Forcing immediate shutdown."), TEXT("Close")); halt = TRUE; } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s trapped. Shutting down."), TEXT("Close")); ctrlCTrapped = TRUE; } quit = TRUE; } /* CTRL_LOGOFF_EVENT */ if (wrapperData->ctrlEventLogoffTrapped) { wrapperData->ctrlEventLogoffTrapped = FALSE; /* Happens when the user logs off. We should quit when run as a */ /* console, but stay up when run as a service. */ if ((wrapperData->isConsole) && (!wrapperData->ignoreUserLogoffs)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("User logged out. Shutting down.")); quit = TRUE; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("User logged out. Ignored.")); quit = FALSE; } } /* CTRL_SHUTDOWN_EVENT */ if (wrapperData->ctrlEventShutdownTrapped) { wrapperData->ctrlEventShutdownTrapped = FALSE; /* Happens when the machine is shutdown or rebooted. Always quit. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Machine is shutting down.")); quit = TRUE; } /* Queued control codes. */ while (wrapperData->ctrlCodeQueueReadIndex != wrapperData->ctrlCodeQueueWriteIndex) { ctrlCodeLast = wrapperData->ctrlCodeQueue[wrapperData->ctrlCodeQueueReadIndex]; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Process queued control code: %d (r:%d w:%d)"), ctrlCodeLast, wrapperData->ctrlCodeQueueReadIndex, wrapperData->ctrlCodeQueueWriteIndex); #endif wrapperData->ctrlCodeQueueReadIndex++; if (wrapperData->ctrlCodeQueueReadIndex >= CTRL_CODE_QUEUE_SIZE ) { wrapperData->ctrlCodeQueueReadIndex = 0; } _sntprintf(buffer, 11, TEXT("%d"), ctrlCodeLast); wrapperProtocolFunction(WRAPPER_MSG_SERVICE_CONTROL_CODE, buffer); } /* SERVICE_CONTROL_PAUSE */ if (wrapperData->ctrlCodePauseTrapped) { wrapperData->ctrlCodePauseTrapped = FALSE; /* Tell the wrapper to pause */ wrapperPauseProcess(WRAPPER_ACTION_SOURCE_CODE_WINDOWS_SERVICE_MANAGER); } /* SERVICE_CONTROL_CONTINUE */ if (wrapperData->ctrlCodeContinueTrapped) { wrapperData->ctrlCodeContinueTrapped = FALSE; /* Tell the wrapper to resume */ wrapperResumeProcess(WRAPPER_ACTION_SOURCE_CODE_WINDOWS_SERVICE_MANAGER); } /* SERVICE_CONTROL_STOP */ if (wrapperData->ctrlCodeStopTrapped) { wrapperData->ctrlCodeStopTrapped = FALSE; /* Request to stop the service. Report SERVICE_STOP_PENDING */ /* to the service control manager before calling ServiceStop() */ /* to avoid a "Service did not respond" error. */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_STOPPING, 0, 0); /* Tell the wrapper to shutdown normally */ /* Always force the shutdown as this is an external event. */ wrapperStopProcess(0, TRUE); /* To make sure that the JVM will not be restarted for any reason, * start the Wrapper shutdown process as well. * In this case we do not want to allow any exit filters to be used * so setting this here will force the shutdown. */ if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { /* Already stopping. */ } else { wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } } /* SERVICE_CONTROL_SHUTDOWN */ if (wrapperData->ctrlCodeShutdownTrapped) { wrapperData->ctrlCodeShutdownTrapped = FALSE; /* Request to stop the service. Report SERVICE_STOP_PENDING */ /* to the service control manager before calling ServiceStop() */ /* to avoid a "Service did not respond" error. */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_STOPPING, 0, 0); /* Tell the wrapper to shutdown normally */ /* Always force the shutdown as this is an external event. */ wrapperStopProcess(0, TRUE); /* To make sure that the JVM will not be restarted for any reason, * start the Wrapper shutdown process as well. */ if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { /* Already stopping. */ } else { wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } } /* The configured thread dump control code */ if (wrapperData->ctrlCodeDumpTrapped) { wrapperData->ctrlCodeDumpTrapped = FALSE; wrapperRequestDumpJVMState(); } if (quit) { if (halt) { /* Disable the thread dump on exit feature if it is set because it * should not be displayed when the user requested the immediate exit. */ wrapperData->requestThreadDumpOnFailedJVMExit = FALSE; wrapperKillProcess(); } else { /* Always force the shutdown as this is an external event. */ wrapperStopProcess(0, TRUE); } /* Don't actually kill the process here. Let the application shut itself down */ /* To make sure that the JVM will not be restarted for any reason, * start the Wrapper shutdown process as well. */ if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { /* Already stopping. */ } else { wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } } } /** * The service control handler is called by the service manager when there are * events for the service. registered using a call to * RegisterServiceCtrlHandler in wrapperServiceMain. * * Note on PowerEvents prior to win2k: http://blogs.msdn.com/heaths/archive/2005/05/18/419791.aspx */ DWORD WINAPI wrapperServiceControlHandlerEx(DWORD dwCtrlCode, DWORD dwEvtType, LPVOID lpEvtData, LPVOID lpCntxt) { DWORD result = result = NO_ERROR; /* Forward the control code off to the JVM. */ DWORD controlCode = dwCtrlCode; /* Enclose the contents of this call in a try catch block so we can * display and log useful information should the need arise. */ __try { /* if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("ServiceControlHandlerEx(%d, %d, %p, %p)"), dwCtrlCode, dwEvtType, lpEvtData, lpCntxt); } */ /* This thread appears to always be the same as the main thread. * Just to be safe reregister it. */ logRegisterThread(WRAPPER_THREAD_MAIN); if (dwCtrlCode == SERVICE_CONTROL_POWEREVENT) { switch (dwEvtType) { case PBT_APMQUERYSUSPEND: /* 0x0 */ /* system is hiberating * send off power resume event */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMQUERYSUSPEND)")); } controlCode = 0x0D00; break; case PBT_APMQUERYSUSPENDFAILED: /* 0x2 */ /* system is waking up * send off power resume event */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMQUERYSUSPENDFAILED)")); } controlCode = 0x0D02; break; case PBT_APMSUSPEND:/* 0x4 */ /* system is waking up * send off power resume event */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMSUSPEND)")); } controlCode = 0x0D04; break; case PBT_APMRESUMECRITICAL: /* 0x6 */ /* system is waking up * send off power resume event */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMRESUMECRITICAL)")); } controlCode = 0x0D06; break; case PBT_APMRESUMESUSPEND: /* 0x7 */ /* system is waking up * send off power resume event */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMRESUMESUSPEND)")); } controlCode = 0x0D07; break; case PBT_APMBATTERYLOW: /* 0x9 */ /* batter is low warning. */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMBATTERYLOW)")); } controlCode = 0x0D09; break; case PBT_APMPOWERSTATUSCHANGE: /* 0xA */ /* the status of system power changed. */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMPOWERSTATUSCHANGE)")); } controlCode = 0x0D0A; break; case PBT_APMOEMEVENT: /* 0xB */ /* there was an OEM event. */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMOEMEVENT)")); } controlCode = 0x0D0B; break; case PBT_APMRESUMEAUTOMATIC: /* 0x12 */ /* system is waking up */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(PBT_APMRESUMEAUTOMATIC)")); } controlCode = 0x0D12; break; /* The following STANDBY values do not appear to be used but are defined in WinUser.h. */ /*case PBT_APMQUERYSTANDBY:*/ /* 0x1 */ /*case PBT_APMQUERYSTANDBYFAILED:*/ /* 0x3 */ /*case PBT_APMSTANDBY:*/ /* 0x5 */ /*case PBT_APMRESUMESTANDBY:*/ /* 0x8 */ default: /* Unexpected generic powerevent code */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT(%d)"), dwEvtType); } break; } } /* Forward the control code off to the JVM. Write the signals into a rotating queue so we can process more than one per loop. */ if ((wrapperData->ctrlCodeQueueWriteIndex == wrapperData->ctrlCodeQueueReadIndex - 1) || ((wrapperData->ctrlCodeQueueWriteIndex == CTRL_CODE_QUEUE_SIZE - 1) && (wrapperData->ctrlCodeQueueReadIndex == 0))) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Control code queue overflow (%d:%d). Dropping control code: %d\n"), wrapperData->ctrlCodeQueueWriteIndex, wrapperData->ctrlCodeQueueReadIndex, controlCode); } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Enqueue control code: %d (r:%d w:%d)"), controlCode, wrapperData->ctrlCodeQueueReadIndex, wrapperData->ctrlCodeQueueWriteIndex); #endif wrapperData->ctrlCodeQueue[wrapperData->ctrlCodeQueueWriteIndex] = controlCode; wrapperData->ctrlCodeQueueWriteIndex++; if (wrapperData->ctrlCodeQueueWriteIndex >= CTRL_CODE_QUEUE_SIZE) { wrapperData->ctrlCodeQueueWriteIndex = 0; wrapperData->ctrlCodeQueueWrapped = TRUE; } } switch(dwCtrlCode) { case SERVICE_CONTROL_PAUSE: if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_PAUSE")); } wrapperData->ctrlCodePauseTrapped = TRUE; break; case SERVICE_CONTROL_CONTINUE: if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_CONTINUE")); } wrapperData->ctrlCodeContinueTrapped = TRUE; break; case SERVICE_CONTROL_STOP: if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_STOP")); } wrapperData->ctrlCodeStopTrapped = TRUE; break; case SERVICE_CONTROL_INTERROGATE: if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_INTERROGATE")); } /* This case MUST be processed, even though we are not */ /* obligated to do anything substantial in the process. */ break; case SERVICE_CONTROL_POWEREVENT: // we handled it if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_POWEREVENT (handled)")); } break; case SERVICE_CONTROL_SHUTDOWN: if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_SHUTDOWN")); } wrapperData->ctrlCodeShutdownTrapped = TRUE; break; default: if ((wrapperData->threadDumpControlCode > 0) && (dwCtrlCode == wrapperData->threadDumpControlCode)) { if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_(%d) Request Thread Dump."), dwCtrlCode); } wrapperData->ctrlCodeDumpTrapped = TRUE; } else { /* Any other cases... Did not handle */ if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT(" SERVICE_CONTROL_(%d) Not handled."), dwCtrlCode); } result = ERROR_CALL_NOT_IMPLEMENTED; } break; } /* After invocation of this function, we MUST call the SetServiceStatus */ /* function, which is accomplished through our ReportStatus function. We */ /* must do this even if the current status has not changed. */ wrapperReportStatus(TRUE, wrapperData->wState, 0, 0); } __except (exceptionFilterFunction(GetExceptionInformation())) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("<-- Wrapper Stopping due to error in service control handler.")); appExit(1); } return result; } /** * The service control handler is called by the service manager when there are * events for the service. registered using a call to * RegisterServiceCtrlHandler in wrapperServiceMain. */ void WINAPI wrapperServiceControlHandler(DWORD dwCtrlCode) { /* if (wrapperData->isDebugging) { log_printf_queue(TRUE, WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Service(%d)"), dwCtrlCode); } */ wrapperServiceControlHandlerEx(dwCtrlCode, 0, NULL, NULL); } /** * The wrapperServiceMain function is the entry point for the NT service. * It is called by the service manager. */ void WINAPI wrapperServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) { int timeout; /* Enclose the contents of this call in a try catch block so we can * display and log useful information should the need arise. */ __try { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("wrapperServiceMain()")); #endif /* Immediately register this thread with the logger. */ logRegisterThread(WRAPPER_THREAD_SRVMAIN); /* Call RegisterServiceCtrlHandler immediately to register a service control */ /* handler function. The returned SERVICE_STATUS_HANDLE is saved with global */ /* scope, and used as a service id in calls to SetServiceStatus. */ if (OptionalRegisterServiceCtrlHandlerEx) { /* Use RegisterServiceCtrlHandlerEx if available. */ sshStatusHandle = OptionalRegisterServiceCtrlHandlerEx( wrapperData->serviceName, wrapperServiceControlHandlerEx, (LPVOID)1); } else { sshStatusHandle = RegisterServiceCtrlHandler( wrapperData->serviceName, wrapperServiceControlHandler); } if (!sshStatusHandle) { goto finally; } /* The global ssStatus SERVICE_STATUS structure contains information about the */ /* service, and is used throughout the program in calls made to SetStatus through */ /* the ReportStatus function. */ ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ssStatus.dwServiceSpecificExitCode = 0; /* Do setup now that the service is initialized. */ /* Initialize the invocation mutex as necessary, exit if it already exists. */ if (initInvocationMutex()) { appExit(1); return; /* For clarity. */ } /* Get the current process. */ wrapperData->wrapperProcess = GetCurrentProcess(); wrapperData->wrapperPID = GetCurrentProcessId(); /* See if the logs should be rolled on Wrapper startup. */ if ((getLogfileRollMode() & ROLL_MODE_WRAPPER) || (getLogfileRollMode() & ROLL_MODE_JVM)) { rollLogs(); } /* Write pid and anchor files as requested. If they are the same file the file is * simply overwritten. */ cleanUpPIDFilesOnExit = TRUE; if (wrapperData->pidFilename) { if (writePidFile(wrapperData->pidFilename, wrapperData->wrapperPID, wrapperData->pidFileUmask, wrapperData->pidFileStrict)) { log_printf (WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not write pid file %s: %s"), wrapperData->pidFilename, getLastErrorText()); appExit(1); return; /* For clarity. */ } } if (wrapperData->anchorFilename) { if (writePidFile(wrapperData->anchorFilename, wrapperData->wrapperPID, wrapperData->anchorFileUmask, FALSE)) { log_printf (WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not write anchor file %s: %s"), wrapperData->anchorFilename, getLastErrorText()); appExit(1); return; /* For clarity. */ } } /* If we could guarantee that all initialization would occur in less than one */ /* second, we would not have to report our status to the service control manager. */ /* For good measure, we will assign SERVICE_START_PENDING to the current service */ /* state and inform the service control manager through our ReportStatus function. */ if (wrapperData->startupTimeout > 0) { timeout = wrapperData->startupTimeout * 1000; } else { timeout = 86400000; // Set infinity at 1 day. } wrapperReportStatus(FALSE, WRAPPER_WSTATE_STARTING, 0, timeout); /* Now actually start the service */ wrapperRunService(); finally: /* Report that the service has stopped and set the correct exit code. */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_STOPPED, wrapperData->exitCode, 1000); #ifdef _DEBUG /* The following message will not always appear on the screen if the STOPPED * status was set above. But the code in the appExit function below always * appears to be getting executed. Looks like some kind of a timing issue. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Exiting service process.")); #endif /* Actually exit the process, returning the current exit code. */ appExit(wrapperData->exitCode); } __except (exceptionFilterFunction(GetExceptionInformation())) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("<-- Wrapper Stopping due to error in service main.")); appExit(1); } } /** * Reads a password from the console and then returns it as a malloced string. * This is only called once so the memory can leak. */ TCHAR *readPassword() { TCHAR *buffer; TCHAR c; int cnt = 0; buffer = malloc(sizeof(TCHAR) * 65); if (!buffer) { outOfMemory(TEXT("RP"), 1); appExit(0); return NULL; } buffer[0] = 0; do { c = _getch(); switch (c) { case 0x03: /* Ctrl-C */ _tprintf(TEXT("\n") ); appExit(0); break; case 0x08: /* Backspace */ if (cnt > 0) { _tprintf(TEXT("%c %c"), 0x08, 0x08); cnt--; buffer[cnt] = 0; } break; case 0xffffffe0: /* Arrow key. */ /* Skip the next character as well. */ _getch(); break; case 0x0d: /* CR */ case 0x0a: /* LF */ /* Done */ break; default: if (cnt < 64) { /* For now, ignore any non-standard ascii characters. */ if ((c >= 0x20) && (c < 0x7f)) { if (wrapperData->ntServicePasswordPromptMask) { printf("*"); } else { _tprintf(TEXT("%c"), c); } buffer[cnt] = c; buffer[cnt + 1] = 0; cnt++; } } break; } /*printf("(%02x)", c);*/ } while ((c != 0x0d) && (c != 0x0a)); _tprintf(TEXT("\n")); return buffer; } /** * RETURNS TRUE if the current Windows OS is Windows Vista or later... */ BOOL isVista() { OSVERSIONINFO osver; osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osver) && osver.dwPlatformId == VER_PLATFORM_WIN32_NT && osver.dwMajorVersion >= 6) { return TRUE; } return FALSE; } /** * RETURNS TRUE if the current Windows OS is Windows XP or later... * http://msdn.microsoft.com/en-us/library/ms724834%28VS.85%29.aspx */ BOOL isWinXP() { OSVERSIONINFO osver; osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osver) && osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { if (osver.dwMajorVersion > 5 || osver.dwMajorVersion == 5 && osver.dwMinorVersion >= 1) { return TRUE; } } return FALSE; } BOOL isElevated() { TOKEN_ELEVATION te = {0}; BOOL bIsElevated = FALSE; HRESULT hResult = E_FAIL; // assume an error occured HANDLE hToken = NULL; DWORD dwReturnLength = 0; if (isVista()) { if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { return bIsElevated ; } if (!GetTokenInformation(hToken, TokenElevation, &te, sizeof(te), &dwReturnLength)) { ; } else { hResult = te.TokenIsElevated ? S_OK : S_FALSE; bIsElevated = (te.TokenIsElevated != 0); } CloseHandle(hToken); return bIsElevated; } else { return TRUE; } } void wrapperCheckForMappedDrives() { TCHAR **propertyNames; TCHAR **propertyValues; long unsigned int *propertyIndices; int i; int advice = 0; if (!wrapperData->ntServiceAccount) { advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.logfile"), TEXT("wrapper.log")), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.logfile.purge.pattern"), TEXT("")), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.pidfile"), NULL), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.java.pidfile"), NULL), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.lockfile"), NULL), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.java.idfile"), NULL), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.statusfile"), NULL), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.java.statusfile"), NULL), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.commandfile"), NULL), advice); advice = wrapperGetUNCFilePath(getFileSafeStringProperty(properties, TEXT("wrapper.anchorfile"), NULL), advice); i = 0; if (getStringProperties(properties, TEXT("wrapper.java.library.path."), TEXT(""), wrapperData->ignoreSequenceGaps, FALSE, &propertyNames, &propertyValues, &propertyIndices)) { /* Failed */ return ; } while (propertyNames[i]) { if (propertyValues[i]) { advice = wrapperGetUNCFilePath(propertyValues[i], advice); i++; } } i = 0; if (getStringProperties(properties, TEXT("wrapper.java.classpath."), TEXT(""), wrapperData->ignoreSequenceGaps, FALSE, &propertyNames, &propertyValues, &propertyIndices)) { /* Failed */ return ; } while (propertyNames[i]) { if (propertyValues[i]) { advice = wrapperGetUNCFilePath(propertyValues[i], advice); i++; } } } } /** * Generates the full binary path to register with the service manager when * installing a service. * * @param buffer Buffer that will hold the binaryPath. If NULL, the required * length will be calculated and stored in reqBufferSize * @param reqBufferSize Pointer to an int that will store the required length in character * of the buffer that was used or is required. * * @return 0 if succeeded. */ int buildServiceBinaryPath(TCHAR *buffer, size_t *reqBufferLen) { DWORD moduleFileNameSize; TCHAR *moduleFileName; DWORD usedLen; TCHAR drive[4]; TCHAR* uncTempBuffer; DWORD uncSize; int pathMapped; int pathMapFailed = FALSE; UNIVERSAL_NAME_INFO* unc; int i; int k; size_t originalSize; if (reqBufferLen) { originalSize = *reqBufferLen; } else { originalSize = 0; } /* We will calculate the size used. */ if (buffer) { buffer[0] = TEXT('\0'); } *reqBufferLen = 1; /* Get the full path and filename of this program. Need to loop to make sure we get it all. */ moduleFileNameSize = 0; moduleFileName = NULL; do { moduleFileNameSize += 100; moduleFileName = malloc(sizeof(TCHAR) * moduleFileNameSize); if (!moduleFileName) { outOfMemory(TEXT("BSBP"), 1); return 1; } /* On Windows XP and 2000, GetModuleFileName will return exactly "moduleFileNameSize" and * leave moduleFileName in an unterminated state in the event that the module file name is too long. * Newer versions of Windows will set the error code to ERROR_INSUFFICIENT_BUFFER but we can't rely on that. */ usedLen = GetModuleFileName(NULL, moduleFileName, moduleFileNameSize); if (usedLen == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to resolve the full Wrapper path - %s"), getLastErrorText()); return 1; } else if ((usedLen == moduleFileNameSize) || (getLastError() == ERROR_INSUFFICIENT_BUFFER)) { /* Buffer too small. Loop again. */ free(moduleFileName); moduleFileName = NULL; } } while (!moduleFileName); /* Always start with the full path to the binary. */ /* If the moduleFileName contains spaces, it needs to be quoted */ /* Resolve to UNC-Name if we are on a mapped drive */ if ((_tcslen(moduleFileName) >= 3) && (moduleFileName[1] == TEXT(':')) && (moduleFileName[2] == TEXT('\\'))) { _tcsncpy(drive, moduleFileName, 3); drive[3] = TEXT('\0'); } else { drive[0] = TEXT('\0'); } pathMapped = FALSE; if ((drive[0] != TEXT('\0')) && (GetDriveType(drive) == DRIVE_REMOTE)) { /* The Wrapper binary is located on a Network Drive. Try to resolve the original Universal path. We need to get a buffer big enough. */ uncSize = 0; moduleFileNameSize = 100; do{ uncTempBuffer = malloc((moduleFileNameSize) * sizeof(TCHAR)); if (!uncTempBuffer) { outOfMemory(TEXT("BSBP"), 2); return 1; } unc = (UNIVERSAL_NAME_INFO *) uncTempBuffer; k = WNetGetUniversalName(moduleFileName, UNIVERSAL_NAME_INFO_LEVEL, unc, &moduleFileNameSize); if (k == ERROR_MORE_DATA) { free(uncTempBuffer); } } while (k == ERROR_MORE_DATA); uncSize = moduleFileNameSize; if (k != NO_ERROR) { if (buffer) { /* Otherwise logged on the next pass. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to resolve Universal Path of mapped network path: %s (%s)"), moduleFileName, getLastErrorText()); } pathMapFailed = TRUE; } else { /* Now we know the size. Create the unc buffer. */ if (_tcschr(unc->lpUniversalName, TEXT(' ')) == NULL) { if (buffer) { _tcsncat(buffer, unc->lpUniversalName, originalSize); } *reqBufferLen += _tcslen(unc->lpUniversalName); } else { if (buffer) { _tcsncat(buffer, TEXT("\""), originalSize); _tcsncat(buffer, unc->lpUniversalName, originalSize); _tcsncat(buffer, TEXT("\""), originalSize); } *reqBufferLen += (1 + _tcslen(unc->lpUniversalName) + 1); } pathMapped = TRUE; free(uncTempBuffer); } } if (!pathMapped) { if (_tcschr(moduleFileName, TEXT(' ')) == NULL) { if (buffer) { _tcsncat(buffer, moduleFileName, originalSize); } *reqBufferLen += _tcslen(moduleFileName); } else { if (buffer) { _tcsncat(buffer, TEXT("\""), originalSize); _tcsncat(buffer, moduleFileName, originalSize); _tcsncat(buffer, TEXT("\""), originalSize); } *reqBufferLen += (1 + _tcslen(moduleFileName) + 1); } } free(moduleFileName); /* Next write the command to start the service. */ if (buffer) { _tcsncat(buffer, TEXT(" -s "), originalSize); } *reqBufferLen += 4; /* Third, the configuration file. */ /* If the wrapperData->configFile contains spaces, it needs to be quoted */ /* Try to convert the config file to a UNC path as well. */ if ((_tcslen(wrapperData->configFile) >= 3) && (wrapperData->configFile[1] == TEXT(':')) && (wrapperData->configFile[2] == TEXT('\\'))) { _tcsncpy(drive, wrapperData->configFile, 3); drive[3] = TEXT('\0'); } else { drive[0] = TEXT('\0'); } pathMapped = FALSE; if ((drive[0] != TEXT('\0')) && (GetDriveType(drive) == DRIVE_REMOTE)) { /* The Wrapper config file is located on a Network Drive. Try to resolve the original Universal path. We need to get a buffer big enough. */ moduleFileNameSize = 100; uncSize = 0; do { uncTempBuffer = malloc((moduleFileNameSize) * sizeof(TCHAR)); if (!uncTempBuffer) { outOfMemory(TEXT("BSBP"), 3); return 1; } unc = (UNIVERSAL_NAME_INFO *) uncTempBuffer; k = WNetGetUniversalName(wrapperData->configFile, UNIVERSAL_NAME_INFO_LEVEL, unc, &moduleFileNameSize); if (k == ERROR_MORE_DATA) { free(uncTempBuffer); } } while (k == ERROR_MORE_DATA); if (k != NO_ERROR) { if (buffer) { /* Otherwise logged on the next pass. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to resolve Universal Path of mapped network path: %s (%s)"), wrapperData->configFile, getLastErrorText()); } pathMapFailed = TRUE; } else { /* Now we know the size. Create the unc buffer. */ if (_tcschr(unc->lpUniversalName, TEXT(' ')) == NULL) { if (buffer) { _tcsncat(buffer, unc->lpUniversalName, originalSize); } *reqBufferLen += _tcslen(unc->lpUniversalName); } else { if (buffer) { _tcsncat(buffer, TEXT("\""), originalSize); _tcsncat(buffer, unc->lpUniversalName, originalSize); _tcsncat(buffer, TEXT("\""), originalSize); } *reqBufferLen += (1 + _tcslen(unc->lpUniversalName) + 1); } pathMapped = TRUE; free(uncTempBuffer); unc = NULL; } } if (!pathMapped) { if (_tcschr(wrapperData->configFile, TEXT(' ')) == NULL) { if (buffer) { _tcsncat(buffer, wrapperData->configFile, originalSize); } *reqBufferLen += _tcslen(wrapperData->configFile); } else { if (buffer) { _tcsncat(buffer, TEXT("\""), originalSize); _tcsncat(buffer, wrapperData->configFile, originalSize); _tcsncat(buffer, TEXT("\""), originalSize); } *reqBufferLen += (1 + _tcslen(wrapperData->configFile) + 1); } } if (pathMapFailed) { if (buffer) { /* Otherwise logged on the next pass. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("There were problems converting mapped network paths the Universal Path format. This may cause the service to fail to start now or when the system is rebooted.")); } } /* All other arguments need to be appended as is. */ for (i = 0; i < wrapperData->argCount; i++) { /* For security reasons, skip the wrapper.ntservice.account and * wrapper.ntservice.password properties if they are declared on the * command line. They will not be needed once the service is * installed. Having them in the registry would be an obvious * security leak. */ if ((_tcsstr(wrapperData->argValues[i], TEXT("wrapper.ntservice.account")) == NULL) && (_tcsstr(wrapperData->argValues[i], TEXT("wrapper.ntservice.password")) == NULL)) { if (buffer) { _tcsncat(buffer, TEXT(" "), originalSize); } *reqBufferLen += 1; /* If the argument contains spaces, it needs to be quoted */ if (_tcschr(wrapperData->argValues[i], TEXT(' ')) == NULL) { if (buffer) { _tcsncat(buffer, wrapperData->argValues[i], originalSize); } *reqBufferLen += _tcslen(wrapperData->argValues[i]); } else { if (buffer) { _tcsncat(buffer, TEXT("\""), originalSize); _tcsncat(buffer, wrapperData->argValues[i], originalSize); _tcsncat(buffer, TEXT("\""), originalSize); } *reqBufferLen += 1 + _tcslen(wrapperData->argValues[i]) + 1; } } } /* If there are any passthrough variables. Then they also need to be appended as is. */ if (wrapperData->javaArgValueCount > 0) { if (buffer) { _tcsncat(buffer, TEXT(" --"), originalSize); } *reqBufferLen += 3; for (i = 0; i < wrapperData->javaArgValueCount; i++) { if (buffer) { _tcsncat(buffer, TEXT(" "), originalSize); } *reqBufferLen += 1; /* If the argument contains spaces, it needs to be quoted */ if (_tcschr(wrapperData->javaArgValues[i], TEXT(' ')) == NULL) { if (buffer) { _tcsncat(buffer, wrapperData->javaArgValues[i], originalSize); } *reqBufferLen += _tcslen(wrapperData->javaArgValues[i]); } else { if (buffer) { _tcsncat(buffer, TEXT("\""), originalSize); _tcsncat(buffer, wrapperData->javaArgValues[i], originalSize); _tcsncat(buffer, TEXT("\""), originalSize); } *reqBufferLen += (1 + _tcslen(wrapperData->javaArgValues[i]) + 1); } } } return 0; } #ifndef STATUS_SUCCESS #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #endif void InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String) { size_t StringLength; if (String == NULL) { LsaString->Buffer = NULL; LsaString->Length = 0; LsaString->MaximumLength = 0; return; } StringLength = wcslen(String); LsaString->Buffer = String; LsaString->Length = (USHORT) StringLength * sizeof(WCHAR); LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR); } NTSTATUS OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle) { LSA_OBJECT_ATTRIBUTES ObjectAttributes; LSA_UNICODE_STRING ServerString; PLSA_UNICODE_STRING Server = NULL; ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); if (ServerName != NULL) { InitLsaString(&ServerString, ServerName); Server = &ServerString; } return LsaOpenPolicy(Server, &ObjectAttributes, DesiredAccess, PolicyHandle); } /* * Checks if pc is part of Domain, workgroup or standalone * @returns 1 if it's part of Domain, 2 for workgroup, 3 for stand alone, 0 if there was an error */ int checkDomain() { LSA_HANDLE PolicyHandle; NTSTATUS status; PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo; PWKSTA_INFO_100 pwkiWorkstationInfo; DWORD netret; wchar_t* ResName; int ret = 0; netret = NetWkstaGetInfo(NULL, 100, (LPBYTE *)&pwkiWorkstationInfo); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("checkDomain: NetWkstaGetInfo returned %d"), netret); #endif if (netret == NERR_Success) { status = OpenPolicy(NULL, GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("checkDomain: OpenPolicy returned %d\n"), status); if (!status) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("checkDomain: LsaQueryInformationPolicy call ahead")); #endif status = LsaQueryInformationPolicy(PolicyHandle, PolicyPrimaryDomainInformation, &ppdiDomainInfo); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("checkDomain: LsaQueryInformationPolicy returned %d"), status); #endif if (!status) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("checkDomain: LsaQueryInformationPolicy:ppdiDomainInfo->maxlen = %d, len=%d, buffer=%s, strlen=%d"), ppdiDomainInfo->Name.MaximumLength,ppdiDomainInfo->Name.Length ,ppdiDomainInfo->Name.Buffer, wcslen(ppdiDomainInfo->Name.Buffer)); #endif ResName = malloc((wcslen(ppdiDomainInfo->Name.Buffer) + 1 ) * sizeof(wchar_t)); if (ResName) { _tcsncpy(ResName, ppdiDomainInfo->Name.Buffer, wcslen(ppdiDomainInfo->Name.Buffer) + 1); if (ppdiDomainInfo->Sid) { ret = 1; } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("checkDomain: comparing %s vs. %s"), ResName, pwkiWorkstationInfo->wki100_computername); #endif if (_tcsncmp(ResName, pwkiWorkstationInfo->wki100_computername, wcslen(pwkiWorkstationInfo->wki100_computername))) { ret = 2; } else { ret = 3; } } free(ResName); } LsaFreeMemory((LPVOID)ppdiDomainInfo); } LsaClose(PolicyHandle); } NetApiBufferFree(pwkiWorkstationInfo); } return ret; } /** * Helperfunction which gets the Security Policy Handle of the specified system * @param referencedDomainName, the system of which the Security Policy Handle should get retrieved * * @return the Handle of the Security Policy, NULL in case of any error */ LSA_HANDLE wrapperGetPolicyHandle(TCHAR* referencedDomainName) { NTSTATUS ntsResult; LSA_HANDLE lsahPolicyHandle; int k; k = checkDomain(); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("checkDomain returns %d."), k); #endif if (k > 0) { if (k > 1) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("OpenPolicy call %s "), referencedDomainName); #endif ntsResult = OpenPolicy(referencedDomainName, /* Name of the target system. */ POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT, /* Desired access permissions. */ &lsahPolicyHandle); /*Receives the policy handle. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("OpenPolicy returns %d."), ntsResult); #endif } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("OpenPolicy call NULL.")); #endif ntsResult = OpenPolicy(NULL, /* Name of the target system. */ POLICY_LOOKUP_NAMES | POLICY_CREATE_ACCOUNT, /* Desired access permissions. */ &lsahPolicyHandle); /*Receives the policy handle. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("OpenPolicy returns %d."), ntsResult); #endif } if (ntsResult != STATUS_SUCCESS) { /* An error occurred. Display it as a win32 error code. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("OpenPolicy failed %lu"), LsaNtStatusToWinError(ntsResult)); return NULL; } } return lsahPolicyHandle; } /** * Helperfunction which gets the SID and domain of a given account name * @param lpszAccountName, the account namespace * @param referencedDomainName, output buffer for the domain * * @return the SID of the account, 0 in case of any error */ PSID wrapperLookupName(LPCTSTR lpszAccountName, WCHAR **referencedDomainName) { PSID Sid; DWORD cbReferencedDomainName, cbSid, lastError; SID_NAME_USE eUse; LPCTSTR formattedAccountName; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("lookupname: %s"), lpszAccountName); #endif if (_tcsstr(lpszAccountName, TEXT(".\\")) == lpszAccountName) { formattedAccountName = lpszAccountName + 2; } else { formattedAccountName= lpszAccountName; } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("lookupname:formatedname %s"), formattedAccountName); #endif cbReferencedDomainName = cbSid = 0; if (LookupAccountName(NULL, formattedAccountName, NULL, &cbSid, NULL, &cbReferencedDomainName, &eUse)) { /* A straight success - that can't be... */ return 0; } lastError = GetLastError(); if (lastError != ERROR_INSUFFICIENT_BUFFER) { /* Any error except the one above is fatal.. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to lookup the account (%s): %d - %s"), lpszAccountName, lastError, getLastErrorText()); return 0; } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("lookupname:cbSID %d ; cbDomain %d"), cbSid, cbReferencedDomainName); #endif if (!(Sid = (PSID)malloc(cbSid))) { outOfMemory(TEXT("WLN"), 1); return 0; } *referencedDomainName = (LPTSTR)calloc((cbReferencedDomainName ), sizeof(TCHAR)); if (!(*referencedDomainName)) { LocalFree(Sid); outOfMemory(TEXT("WLN"), 2); return 0; } if (!LookupAccountName(NULL, formattedAccountName, Sid, &cbSid, *referencedDomainName, &cbReferencedDomainName, &eUse)) { free(*referencedDomainName); free(Sid); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to lookup the account (%s): %d - %s"), lpszAccountName, lastError, getLastErrorText()); return 0; } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("lookupname:cbreferencedDomain %s"), *referencedDomainName); #endif return Sid; } /** * This functions adds the Logon as Service privileges to the user account * * @param the account name for which the privilege should be added. * * @return FALSE if successful, TRUE otherwise */ BOOL wrapperAddPrivileges(TCHAR *account) { PLSA_UNICODE_STRING pointer; NTSTATUS ntsResult; LSA_HANDLE PolicyHandle; PSID AccountSID; TCHAR *referencedDomainName; ULONG counter = 1; WCHAR privileges[] = SE_SERVICE_LOGON_NAME; int retVal = TRUE; AccountSID = wrapperLookupName(account, &referencedDomainName); if (AccountSID) { if ((PolicyHandle = wrapperGetPolicyHandle(referencedDomainName)) != NULL) { /* Create an LSA_UNICODE_STRING for the privilege names. */ pointer = malloc(sizeof(LSA_UNICODE_STRING)); if (pointer == NULL) { outOfMemory(TEXT("WAP"), 1); } else { InitLsaString(pointer, privileges); ntsResult = LsaAddAccountRights(PolicyHandle, /* An open policy handle. */ AccountSID, /* The target SID. */ pointer, /* The privileges. */ counter); /* Number of privileges. */ free(pointer); if (ntsResult == STATUS_SUCCESS) { retVal = FALSE; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to add Logon As Service Permission: %lu"), LsaNtStatusToWinError(ntsResult)); } } LsaClose(PolicyHandle); } free(AccountSID); free(referencedDomainName); } return retVal; } /** * Install the Wrapper as an NT Service using the information and service * name in the current configuration file. * * Stores the parameters with the service name so that the wrapper.conf file * can be located at runtime. */ int wrapperInstall() { SC_HANDLE schService; SC_HANDLE schSCManager; DWORD serviceType; DWORD startType; size_t binaryPathLen; TCHAR *binaryPath; int result = 0; HKEY hKey; TCHAR regPath[ 1024 ]; TCHAR domain[ 1024 ]; TCHAR account[ 1024 ]; TCHAR *tempAccount; TCHAR *ntServicePassword; DWORD dsize = 1024, dwDesiredAccess; /* Initialization */ dwDesiredAccess = 0; /* Generate the service binary path. We need to figure out how big the buffer needs to be. */ if (buildServiceBinaryPath(NULL, &binaryPathLen)) { /* Failed a reason should have been given. But show result. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to install the %s service"), wrapperData->serviceDisplayName); return 1; } binaryPath = malloc(binaryPathLen * sizeof(TCHAR)); if (!binaryPath) { outOfMemory(TEXT("WI"), 1); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to install the %s service"), wrapperData->serviceDisplayName); return 1; } if (buildServiceBinaryPath(binaryPath, &binaryPathLen)) { /* Failed a reason should have been given. But show result. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to install the %s service"), wrapperData->serviceDisplayName); free(binaryPath); return 1; } if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Service command: %s"), binaryPath); } if (wrapperData->ntServicePrompt) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Prompting for account (DOMAIN\\ACCOUNT)...")); _tprintf(TEXT("Please input the domain name [%s]: "), wrapperData->domainName); if (isElevated() && getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL) { _tprintf(TEXT("n")); fflush(NULL); } _fgetts(domain, dsize, stdin); if (!domain || _tcscmp(domain, TEXT("\n")) == 0) { _sntprintf(domain, dsize, TEXT("%s"), wrapperData->domainName); } else if (domain[_tcslen(domain) - 1] == TEXT('\n')) { domain[_tcslen(domain) - 1] = TEXT('\0'); } _tprintf(TEXT("Please input the account name [%s]: "), wrapperData->userName); if (isElevated() && getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL) { _tprintf(TEXT("n")); fflush(NULL); } _fgetts(account, dsize, stdin); if (!account || _tcscmp(account, TEXT("\n")) == 0) { _sntprintf(account, dsize, TEXT("%s"), wrapperData->userName); } else if (account[_tcslen(account) - 1] == TEXT('\n')) { account[_tcslen(account) - 1] = TEXT('\0'); } tempAccount = malloc((_tcslen(domain) + _tcslen(account) + 2) * sizeof(TCHAR)); if (!tempAccount) { outOfMemory(TEXT("WI"), 2); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to install the %s service"), wrapperData->serviceDisplayName); free(binaryPath); return 1; } _sntprintf(tempAccount, _tcslen(domain) + _tcslen(account) + 2, TEXT("%s\\%s"), domain, account); updateStringValue(&wrapperData->ntServiceAccount, tempAccount); free(tempAccount); } if (wrapperData->ntServiceAccount && wrapperData->ntServicePasswordPrompt) { /* Prompt the user for a password. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Prompting for account password...")); _tprintf(TEXT("Please input the password for account '%s': "), wrapperData->ntServiceAccount); if (isElevated() && getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL) { _tprintf(TEXT("p")); fflush(NULL); /* as this here is from the secondary instance we can read with _fgetts */ wrapperData->ntServicePassword = calloc(65, sizeof(TCHAR)); if (!wrapperData->ntServicePassword) { outOfMemory(TEXT("WI"), 21); free(binaryPath); return 1; } _fgetts(wrapperData->ntServicePassword, 65, stdin); } else { wrapperData->ntServicePassword = readPassword(); } } /* Decide on the service type */ if (wrapperData->ntServiceInteractive) { serviceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; } else { serviceType = SERVICE_WIN32_OWN_PROCESS; } /* Next, get a handle to the service control manager */ schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE ); if (schSCManager) { if (wrapperData->ntServiceAccount && wrapperAddPrivileges(wrapperData->ntServiceAccount)) { /* adding failed it was reported already above */ } /* Make sure that an empty length password is null. */ ntServicePassword = wrapperData->ntServicePassword; if ((ntServicePassword != NULL) && (_tcslen(ntServicePassword) <= 0)) { ntServicePassword = NULL; } startType = wrapperData->ntServiceStartType; if (result != 1) { schService = CreateService(schSCManager, /* SCManager database */ wrapperData->serviceName, /* name of service */ wrapperData->serviceDisplayName, /* name to display */ dwDesiredAccess, /* desired access */ serviceType, /* service type */ startType, /* start type */ SERVICE_ERROR_NORMAL, /* error control type */ binaryPath, /* service's binary */ wrapperData->ntServiceLoadOrderGroup, /* load ordering group */ NULL, /* tag identifier not used because they are used for driver level services. */ wrapperData->ntServiceDependencies, /* dependencies */ wrapperData->ntServiceAccount, /* LocalSystem account if NULL */ ntServicePassword); /* NULL or empty for no password */ if (schService) { /* Have the service, add a description to the registry. */ _sntprintf(regPath, 1024, TEXT("SYSTEM\\CurrentControlSet\\Services\\%s"), wrapperData->serviceName); if ((wrapperData->serviceDescription != NULL && _tcslen(wrapperData->serviceDescription) > 0) && (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regPath, 0, KEY_WRITE, (PHKEY) &hKey) == ERROR_SUCCESS)) { /* Set Description key in registry */ RegSetValueEx(hKey, TEXT("Description"), (DWORD) 0, (DWORD) REG_SZ, (LPBYTE)wrapperData->serviceDescription, (int)(sizeof(TCHAR) * (_tcslen(wrapperData->serviceDescription) + 1))); RegCloseKey(hKey); } if (result !=1) { /* Service was installed. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s service installed."), wrapperData->serviceDisplayName); } /* Close the handle to this service object */ CloseServiceHandle(schService); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to install the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } /* Close the handle to the service control manager database */ CloseServiceHandle(schSCManager); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to install the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); if (isVista() && !isElevated()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Performing this action requires that you run as an elevated process.")); } result = 1; } return result; } void closeRegistryKey(HKEY hKey) { LONG result; LPSTR pBuffer = NULL; result = RegCloseKey(hKey); if (result != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to close the registry: %d : %s"), result, pBuffer); LocalFree(pBuffer); } } /** * Sets any environment variables stored in the system registry to the current * environment. The NT service environment only has access to the environment * variables set when the machine was last rebooted. This makes it possible * to access the latest values in registry without a reboot. * * Note that this function is always called before the configuration file has * been loaded this means that any logging that takes place will be sent to * the default log file which may be difficult for the user to locate. * * Return TRUE if there were any problems. */ int wrapperLoadEnvFromRegistryInner(HKEY baseHKey, const TCHAR *regPath, int appendPath, int source) { LONG result; LPSTR pBuffer = NULL; int envCount = 0; int ret; HKEY hKey; DWORD dwIndex; DWORD valueCount; DWORD maxValueNameLength; DWORD maxValueLength; TCHAR *valueName; TCHAR *value; DWORD thisValueNameLength; DWORD thisValueLength; DWORD thisValueType; const TCHAR *oldVal; TCHAR *newVal; BOOL expanded; /* NOTE - Any log output here will be placed in the default log file as it happens * before the wrapper.conf is loaded. */ /* Open the registry entry where the current environment variables are stored. */ result = RegOpenKeyEx(baseHKey, regPath, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, (PHKEY)&hKey); if (result == ERROR_SUCCESS) { /* Read in each of the environment variables and set them into the environment. * These values will be set as is without doing any environment variable * expansion. In order for the ExpandEnvironmentStrings function to work all * of the environment variables to be replaced must already be set. To handle * this, after we set the values as is from the registry, we need to go back * through all the ones we set and Expand them if necessary. */ /* Query the registry to find out how many values there are as well as info about how * large the values names and data are. */ result = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &valueCount, &maxValueNameLength, &maxValueLength, NULL, NULL); if (result != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to query the registry to get the environment: %d : %s"), result, pBuffer); LocalFree(pBuffer); closeRegistryKey(hKey); return TRUE; } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Registry contains %d variables. Longest name=%d, longest value=%d"), valueCount, maxValueNameLength, maxValueLength); #endif /* Add space for the null. */ maxValueNameLength++; maxValueLength++; /* Allocate buffers to get the value names and values from the registry. These can * be reused because we are using the setEnv function to store the values into the * environment. setEnv allocates the memory required by the environment. */ valueName = malloc(sizeof(TCHAR) * maxValueNameLength); if (!valueName) { outOfMemory(TEXT("WLEFRI"), 1); closeRegistryKey(hKey); return TRUE; } value = malloc(sizeof(TCHAR) * maxValueLength); if (!valueName) { outOfMemory(TEXT("WLEFRI"), 2); closeRegistryKey(hKey); return TRUE; } /* Loop over the values and load each of them into the local environment as is. */ dwIndex = 0; do { thisValueNameLength = maxValueNameLength; thisValueLength = maxValueLength; result = RegEnumValue(hKey, dwIndex, valueName, &thisValueNameLength, NULL, &thisValueType, (LPBYTE)value, &thisValueLength); if (result == ERROR_SUCCESS) { if ((thisValueType == REG_SZ) || (thisValueType = REG_EXPAND_SZ)) { /* Got a value. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loaded var name=\"%s\", value=\"%s\""), valueName, value); #endif if (appendPath && (strcmpIgnoreCase(TEXT("path"), valueName) == 0)) { /* The PATH variable is special, it needs to be appended to the existing value. */ oldVal = _tgetenv(TEXT("PATH")); if (oldVal) { newVal = malloc(sizeof(TCHAR) * (_tcslen(oldVal) + 1 + _tcslen(value) + 1)); if (!newVal) { outOfMemory(TEXT("WLEFRI"), 3); closeRegistryKey(hKey); return TRUE; } _sntprintf(newVal, _tcslen(oldVal) + 1 + _tcslen(value) + 1, TEXT("%s;%s"), oldVal, value); if (setEnv(valueName, newVal, source)) { /* Already reported. */ free(newVal); closeRegistryKey(hKey); return TRUE; } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Appended to existing value: %s=%s"), valueName, newVal); #endif free(newVal); } else { /* Did not exist, set normally. */ if (setEnv(valueName, value, source)) { /* Already reported. */ closeRegistryKey(hKey); return TRUE; } } } else { if (setEnv(valueName, value, source)) { /* Already reported. */ closeRegistryKey(hKey); return TRUE; } } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Set to local environment.")); #endif } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loaded var name=\"%s\" but type is invalid: %d, skipping."), valueName, thisValueType); #endif } } else if (result = ERROR_NO_MORE_ITEMS) { /* This means we are at the end. Fall through. */ } else { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to query the registry to get environment variable #%d: %d : %s"), dwIndex, result, getLastErrorText()); LocalFree(pBuffer); closeRegistryKey(hKey); return TRUE; } dwIndex++; } while (result != ERROR_NO_MORE_ITEMS); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("All environment variables loaded. Loop back over them to evaluate any nested variables.")); #endif /* Go back and loop over the environment variables we just set and expand any * variables which contain % characters. Loop until we make a pass which does * not perform any replacements. */ do { expanded = FALSE; dwIndex = 0; do { thisValueNameLength = maxValueNameLength; result = RegEnumValue(hKey, dwIndex, valueName, &thisValueNameLength, NULL, &thisValueType, NULL, NULL); if (result == ERROR_SUCCESS) { /* Found an environment variable in the registry. Variables that contain references have a different type. */ if (thisValueType = REG_EXPAND_SZ) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Get the current local value of variable \"%s\""), valueName); #endif oldVal = _tgetenv(valueName); if (oldVal == NULL) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" The current local value of variable \"%s\" is null, meaning it was not in the registry. Skipping."), valueName); #endif } else { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" \"%s\"=\"%s\""), valueName, oldVal); #endif if (_tcschr(oldVal, TEXT('%'))) { /* This variable contains tokens which need to be expanded. */ /* Find out how much space is required to store the expanded value. */ ret = ExpandEnvironmentStrings(oldVal, NULL, 0); if (ret == 0) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { /* The ExpandEnvironmentStrings function has an internal 32k size limit. We hit it. * All we can do is skip this particular variable by leaving it unexpanded. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to expand environment variable \"%s\" because the result is larger than the system allowed 32k. Leaving unexpanded and continuing."), valueName); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to expand environment variable \"%s\": %s"), valueName, getLastErrorText()); closeRegistryKey(hKey); return TRUE; } } else { /* Allocate a buffer to hold to the expanded value. */ newVal = malloc(sizeof(TCHAR) * (ret + 2)); if (!newVal) { outOfMemory(TEXT("WLEFRI"), 4); closeRegistryKey(hKey); return TRUE; } /* Actually expand the variable. */ ret = ExpandEnvironmentStrings(oldVal, newVal, ret + 2); if (ret == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to expand environment variable \"%s\" (2): %s"), valueName, getLastErrorText()); free(newVal); closeRegistryKey(hKey); return TRUE; } /* Was anything changed? */ if (_tcscmp(oldVal, newVal) == 0) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Value unchanged. Referenced environment variable not set.")); #endif } else { /* Set the expanded environment variable */ expanded = TRUE; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Update local environment variable. \"%s\"=\"%s\""), valueName, newVal); #endif /* Update the environment. */ if (setEnv(valueName, newVal, source)) { /* Already reported. */ free(newVal); closeRegistryKey(hKey); return TRUE; } } free(newVal); } } } } } else if (result == ERROR_NO_MORE_ITEMS) { /* No more environment variables. */ } else { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to read registry - %s"), getLastErrorText()); LocalFree(pBuffer); closeRegistryKey(hKey); return TRUE; } dwIndex++; } while (result != ERROR_NO_MORE_ITEMS); #ifdef _DEBUG if (expanded) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Rescan environment variables to varify that there are no more expansions necessary.")); } #endif } while (expanded); #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Done loading environment variables.")); #endif /* Close the registry entry */ closeRegistryKey(hKey); } else { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to access registry to obtain environment variables - %s"), getLastErrorText()); LocalFree(pBuffer); return TRUE; } return FALSE; } /** * Loads the environment stored in the registry. * * (Only called for versions of Windows older than XP or 2003.) * * Return TRUE if there were any problems. */ int wrapperLoadEnvFromRegistry() { /* We can't access any properties here as they are not yet loaded when called. */ /* Always load in the system wide variables. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Loading System environment variables from Registry:")); #endif if (wrapperLoadEnvFromRegistryInner(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\\"), FALSE, ENV_SOURCE_REG_SYSTEM)) { return TRUE; } /* Only load in the user specific variables if the USERNAME environment variable is set. */ if (_tgetenv(TEXT("USERNAME"))) { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Loading Account environment variables from Registry:")); #endif if (wrapperLoadEnvFromRegistryInner(HKEY_CURRENT_USER, TEXT("Environment\\"), TRUE, ENV_SOURCE_REG_ACCOUNT)){ return TRUE; } } return FALSE; } /** * Gets the JavaHome absolute path from the windows registry */ int wrapperGetJavaHomeFromWindowsRegistry(TCHAR *javaHome) { LONG result; LPSTR pBuffer = NULL; const TCHAR *prop; TCHAR *c; TCHAR subKey[512]; /* Registry subkey that jvm creates when is installed */ TCHAR *valueKey; TCHAR jreversion[10]; /* Will receive a registry value that has jvm version */ HKEY baseHKey; HKEY openHKey = NULL; /* Will receive the handle to the opened registry key */ DWORD valueType; DWORD valueSize; TCHAR *value; prop = getStringProperty(properties, TEXT("wrapper.registry.java_home"), NULL); if (prop) { /* A registry location was specified. */ if (_tcsstr(prop, TEXT("HKEY_CLASSES_ROOT\\")) == prop) { baseHKey = HKEY_CLASSES_ROOT; _tcsncpy(subKey, prop + 18, 512); } else if (_tcsstr(prop, TEXT("HKEY_CURRENT_CONFIG\\")) == prop) { baseHKey = HKEY_CURRENT_USER; _tcsncpy(subKey, prop + 20, 512); } else if (_tcsstr(prop, TEXT("HKEY_CURRENT_USER\\")) == prop) { baseHKey = HKEY_CURRENT_USER; _tcsncpy(subKey, prop + 18, 512); } else if (_tcsstr(prop, TEXT("HKEY_LOCAL_MACHINE\\")) == prop) { baseHKey = HKEY_LOCAL_MACHINE; _tcsncpy(subKey, prop + 19, 512); } else if (_tcsstr(prop, TEXT("HKEY_USERS\\")) == prop) { baseHKey = HKEY_USERS; _tcsncpy(subKey, prop + 11, 512); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("wrapper.registry.java_home does not begin with a known root key: %s"), prop); return 0; } /* log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("subKey=%s"), subKey); */ /* We need to split the value from the key. Find the last \ */ c = _tcsrchr(subKey, TEXT('\\')); if (!c) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("wrapper.registry.java_home is an invalid key: %s"), prop); return 0; } valueKey = c + 1; /* Truncate the subKey. */ *c = TEXT('\0'); /*log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("subKey=%s valueKey=%s"), subKey, valueKey); */ /* * Opens the Registry Key needed to query the jvm version */ result = RegOpenKeyEx(baseHKey, subKey, 0, KEY_QUERY_VALUE, &openHKey); if (result != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to access configured registry location for JAVA_HOME: %s - (%d)"), subKey, errno); LocalFree(pBuffer); return 0; } result = RegQueryValueEx(openHKey, valueKey, NULL, &valueType, NULL, &valueSize); if (result != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to access configured registry location for JAVA_HOME: %s - (%d)"), prop, errno); LocalFree(pBuffer); closeRegistryKey(openHKey); return 0; } if (valueType != REG_SZ) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Configured JAVA_HOME registry location is not of type REG_SZ: %s"), prop); closeRegistryKey(openHKey); return 0; } value = malloc(sizeof(TCHAR) * valueSize); if (!value) { outOfMemory(TEXT("WGJFWR"), 1); closeRegistryKey(openHKey); return 0; } result = RegQueryValueEx(openHKey, valueKey, NULL, &valueType, (LPBYTE)value, &valueSize); if (result != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to access configured registry location %s - (%d)"), prop, errno); LocalFree(pBuffer); free(value); closeRegistryKey(openHKey); return 0; } closeRegistryKey(openHKey); /* Returns the JavaHome path */ _tcsncpy(javaHome, value, 512); free(value); return 1; } else { /* Look for the java_home in the default location. */ /* SubKey containing the jvm version */ _tcsncpy(subKey, TEXT("SOFTWARE\\JavaSoft\\Java Runtime Environment"), 512); /* * Opens the Registry Key needed to query the jvm version */ result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_QUERY_VALUE, &openHKey); if (result != ERROR_SUCCESS) { /* Not found. continue. */ return 0; } /* * Queries for the jvm version */ valueSize = sizeof(jreversion); result = RegQueryValueEx(openHKey, TEXT("CurrentVersion"), NULL, &valueType, (LPBYTE)jreversion, &valueSize); if (result != ERROR_SUCCESS) { closeRegistryKey(openHKey); return 0; } closeRegistryKey(openHKey); /* adds the jvm version to the subkey */ _tcsncat(subKey, TEXT("\\"), 512); _tcsncat(subKey, jreversion, 512); /* * Opens the Registry Key needed to query the JavaHome */ result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_QUERY_VALUE, &openHKey); if (result != ERROR_SUCCESS) { return 0; } /* * Queries for the JavaHome */ result = RegQueryValueEx(openHKey, TEXT("JavaHome"), NULL, &valueType, NULL, &valueSize); if (result != ERROR_SUCCESS) { closeRegistryKey(openHKey); return 0; } value = malloc(sizeof(TCHAR) * valueSize); if (!value) { outOfMemory(TEXT("WGJFWR"), 2); closeRegistryKey(openHKey); return 0; } result = RegQueryValueEx(openHKey, TEXT("JavaHome"), NULL, &valueType, (LPBYTE)value, &valueSize); if (result != ERROR_SUCCESS) { closeRegistryKey(openHKey); return 0; } closeRegistryKey(openHKey); /* Returns the JavaHome path */ _tcsncpy(javaHome, value, 512); free(value); return 1; } } TCHAR *getNTServiceStatusName(int status) { TCHAR *name; switch(status) { case SERVICE_STOPPED: name = TEXT("STOPPED"); break; case SERVICE_START_PENDING: name = TEXT("START_PENDING"); break; case SERVICE_STOP_PENDING: name = TEXT("STOP_PENDING"); break; case SERVICE_RUNNING: name = TEXT("RUNNING"); break; case SERVICE_CONTINUE_PENDING: name = TEXT("CONTINUE_PENDING"); break; case SERVICE_PAUSE_PENDING: name = TEXT("PAUSE_PENDING"); break; case SERVICE_PAUSED: name = TEXT("PAUSED"); break; default: name = TEXT("UNKNOWN"); break; } return name; } /** Starts a Wrapper instance running as an NT Service. */ int wrapperStartService() { SC_HANDLE schService; SC_HANDLE schSCManager; SERVICE_STATUS serviceStatus; const TCHAR *path; TCHAR wrapperFullPath[FILEPATHSIZE] = TEXT(""); TCHAR logFileFullPath[FILEPATHSIZE] = TEXT(""); TCHAR defaultLogFileFullPath[FILEPATHSIZE] = TEXT(""); TCHAR *status; int msgCntr; int stopping; int result; int errorCode; /* Wrapper binary. */ path = wrapperData->argBinary; result = GetFullPathName(path, FILEPATHSIZE, wrapperFullPath, NULL); if (result >= FILEPATHSIZE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The full path of %s is too large. (%d)"), path, result); _tcsncpy(wrapperFullPath, path, FILEPATHSIZE); } else if (result == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to resolve the full path of %s : %s"), path, getLastErrorText()); _tcsncpy(wrapperFullPath, path, FILEPATHSIZE); } /* Log file path. */ path = getLogfilePath(); result = GetFullPathName(path, FILEPATHSIZE, logFileFullPath, NULL); if (result >= FILEPATHSIZE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The full path of %s is too large. (%d)"), path, result); _tcsncpy(logFileFullPath, path, FILEPATHSIZE); } else if (result == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to resolve the full path of %s : %s"), path, getLastErrorText()); _tcsncpy(logFileFullPath, path, FILEPATHSIZE); } /* Default Log file path. */ path = getDefaultLogfilePath(); result = GetFullPathName(path, FILEPATHSIZE, defaultLogFileFullPath, NULL); if (result >= FILEPATHSIZE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The full path of %s is too large. (%d)"), path, result); _tcsncpy(defaultLogFileFullPath, path, FILEPATHSIZE); } else if (result == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to resolve the full path of %s : %s"), path, getLastErrorText()); _tcsncpy(defaultLogFileFullPath, path, FILEPATHSIZE); } result = 0; /* First, get a handle to the service control manager */ schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (schSCManager) { /* Next get the handle to this service... */ schService = OpenService(schSCManager, wrapperData->serviceName, SERVICE_QUERY_STATUS | SERVICE_START); if (schService) { /* Make sure that the service is not already running. */ if (QueryServiceStatus(schService, &serviceStatus)) { if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { /* The service is stopped, so try starting it. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Starting the %s service..."), wrapperData->serviceDisplayName); if (StartService(schService, 0, NULL)) { /* We will get here immediately if the service process was launched. * We still need to wait for it to actually start. */ msgCntr = 0; stopping = FALSE; do { if (QueryServiceStatus(schService, &serviceStatus)) { if (serviceStatus.dwCurrentState == SERVICE_STOP_PENDING) { if (!stopping) { stopping = TRUE; msgCntr = 5; /* Trigger a message */ } if (msgCntr >= 5) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Stopping...")); msgCntr = 0; } } else { if (msgCntr >= 5) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Waiting to start...")); msgCntr = 0; } } wrapperSleep(1000); msgCntr++; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; break; } } while ((serviceStatus.dwCurrentState != SERVICE_STOPPED) && (serviceStatus.dwCurrentState != SERVICE_RUNNING) && (serviceStatus.dwCurrentState != SERVICE_PAUSED)); /* Was the service started? */ if (serviceStatus.dwCurrentState == SERVICE_RUNNING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s started."), wrapperData->serviceDisplayName); } else if (serviceStatus.dwCurrentState == SERVICE_PAUSED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s started but immediately paused.."), wrapperData->serviceDisplayName); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s service was launched, but failed to start."), wrapperData->serviceDisplayName); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Please check the log file more information: %s"), logFileFullPath); result = 1; } } else { errorCode = GetLastError(); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to start the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); switch (errorCode) { case ERROR_ACCESS_DENIED: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Advice:" )); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Usually when the Windows Service Manager does not have access to the Wrapper\nbinary, it is caused by a file permission problem preventing the user running\nthe Wrapper from accessing it. Please check the permissions on the file and\nits parent directories." )); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT(" Wrapper Binary : %s"), wrapperFullPath); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); break; case ERROR_SERVICE_REQUEST_TIMEOUT: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Advice:" )); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Usually when the Windows Service Manager times out waiting for the Wrapper\nprocess to launch it is caused by a file permission problem preventing the\nWrapper from reading its configuration file and/or writing to its log file.\nPlease check the permissions on both files and their parent directories.\nIf there are no messages in either the configured or default log file, please\nalso check the Windows Event Log." )); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT(" Configuration File : %s"), wrapperData->argConfFile); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT(" Congigured Log File : %s" ), logFileFullPath); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT(" Default Log File : %s" ), defaultLogFileFullPath); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); break; default: break; } result = 1; } } else { status = getNTServiceStatusName(serviceStatus.dwCurrentState); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s service is already running with status: %s"), wrapperData->serviceDisplayName, status); result = 1; } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } /* Close this service object's handle to the service control manager */ CloseServiceHandle(schService); } else { if (GetLastError() == ERROR_ACCESS_DENIED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to start the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); if (isVista() && !isElevated()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Performing this action requires that you run as an elevated process.")); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s service is not installed - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } result = 1; } /* Finally, close the handle to the service control manager's database */ CloseServiceHandle(schSCManager); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to start the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } return result; } /** Stops a Wrapper instance running as an NT Service. */ int wrapperStopService(int command) { SC_HANDLE schService; SC_HANDLE schSCManager; SERVICE_STATUS serviceStatus; TCHAR *status; int msgCntr; int result = 0; /* First, get a handle to the service control manager */ schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (schSCManager) { /* Next get the handle to this service... */ schService = OpenService(schSCManager, wrapperData->serviceName, SERVICE_QUERY_STATUS | SERVICE_STOP); if (schService) { /* Find out what the current status of the service is so we can decide what to do. */ if (QueryServiceStatus(schService, &serviceStatus)) { if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { if (command) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was not running."), wrapperData->serviceDisplayName); } } else { if (serviceStatus.dwCurrentState == SERVICE_STOP_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was already in the process of stopping."), wrapperData->serviceDisplayName); } else { /* Stop the service. */ if (ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus)) { if (command) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Stopping the %s service..."), wrapperData->serviceDisplayName); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Service is running. Stopping it...")); } } else { if (serviceStatus.dwCurrentState == SERVICE_START_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of starting. Stopping it..."), wrapperData->serviceDisplayName); } else { status = getNTServiceStatusName(serviceStatus.dwCurrentState); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Attempt to stop the %s service failed. Status: %s"), wrapperData->serviceDisplayName, status); result = 1; } } } if (result == 0) { /* Wait for the service to stop. */ msgCntr = 0; do { if (QueryServiceStatus(schService, &serviceStatus)) { if (msgCntr >= 5) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Waiting to stop...")); msgCntr = 0; } wrapperSleep(1000); msgCntr++; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; break; } } while (serviceStatus.dwCurrentState != SERVICE_STOPPED); if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s stopped."), wrapperData->serviceDisplayName); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Failed to stop the %s service."), wrapperData->serviceDisplayName); result = 1; } } } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } /* Close this service object's handle to the service control manager */ CloseServiceHandle(schService); } else { if (GetLastError() == ERROR_ACCESS_DENIED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to stop the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); if (isVista() && !isElevated()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Performing this action requires that you run as an elevated process.")); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s service is not installed - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } result = 1; } /* Finally, close the handle to the service control manager's database */ CloseServiceHandle(schSCManager); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to stop the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } return result; } /** Pauses a Wrapper instance running as an NT Service. */ int wrapperPauseService() { SC_HANDLE schService; SC_HANDLE schSCManager; SERVICE_STATUS serviceStatus; TCHAR *status; int msgCntr; int result = 0; /* First, get a handle to the service control manager */ schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (schSCManager) { /* Next get the handle to this service... */ schService = OpenService(schSCManager, wrapperData->serviceName, SERVICE_QUERY_STATUS | SERVICE_PAUSE_CONTINUE); if (schService) { /* Make sure that the service is in a state that can be paused. */ if (QueryServiceStatus(schService, &serviceStatus)) { if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was not running."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_STOP_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of stopping."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_PAUSED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was already paused."), wrapperData->serviceDisplayName); } else if (serviceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of being paused."), wrapperData->serviceDisplayName); } else { /* The service is started, starting, or resuming, so try pausing it. */ if (ControlService(schService, SERVICE_CONTROL_PAUSE, &serviceStatus)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Pausing the %s service..."), wrapperData->serviceDisplayName); } else { status = getNTServiceStatusName(serviceStatus.dwCurrentState); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Attempt to pause the %s service failed. Status: %s"), wrapperData->serviceDisplayName, status); result = 1; } } if (result == 0) { /* Wait for the service to pause. */ msgCntr = 0; do { if (QueryServiceStatus(schService, &serviceStatus)) { if (msgCntr >= 5) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Waiting to pause...")); msgCntr = 0; } wrapperSleep(1000); msgCntr++; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; break; } } while (!((serviceStatus.dwCurrentState == SERVICE_PAUSED) || (serviceStatus.dwCurrentState == SERVICE_STOPPED))); if (serviceStatus.dwCurrentState == SERVICE_PAUSED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s service paused."), wrapperData->serviceDisplayName); } else { status = getNTServiceStatusName(serviceStatus.dwCurrentState); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Failed to pause %s service. Status: %s"), wrapperData->serviceDisplayName, status); result = 1; } } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } /* Close this service object's handle to the service control manager */ CloseServiceHandle(schService); } else { if (GetLastError() == ERROR_ACCESS_DENIED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to pause the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s service is not installed - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } result = 1; } /* Finally, close the handle to the service control manager's database */ CloseServiceHandle(schSCManager); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to pause the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); if (isVista() && !isElevated()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Performing this action requires that you run as an elevated process.")); } result = 1; } return result; } /** Resume a Wrapper instance running as an NT Service. */ int wrapperResumeService() { SC_HANDLE schService; SC_HANDLE schSCManager; SERVICE_STATUS serviceStatus; TCHAR *status; int msgCntr; int result = 0; /* First, get a handle to the service control manager */ schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (schSCManager) { /* Next get the handle to this service... */ schService = OpenService(schSCManager, wrapperData->serviceName, SERVICE_QUERY_STATUS | SERVICE_PAUSE_CONTINUE); if (schService) { /* Make sure that the service is in a state that can be resumed. */ if (QueryServiceStatus(schService, &serviceStatus)) { if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was not running."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_STOP_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of stopping."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of being paused."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of being resumed."), wrapperData->serviceDisplayName); } else if (serviceStatus.dwCurrentState == SERVICE_RUNNING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was already started."), wrapperData->serviceDisplayName); } else { /* The service is paused, so try resuming it. */ if (ControlService(schService, SERVICE_CONTROL_CONTINUE, &serviceStatus)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Resuming the %s service..."), wrapperData->serviceDisplayName); } else { status = getNTServiceStatusName(serviceStatus.dwCurrentState); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Attempt to resume the %s service failed. Status: %s"), wrapperData->serviceDisplayName, status); result = 1; } } if (result == 0) { /* Wait for the service to resume. */ msgCntr = 0; do { if (QueryServiceStatus(schService, &serviceStatus)) { if (msgCntr >= 5) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Waiting to resume...")); msgCntr = 0; } wrapperSleep(1000); msgCntr++; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; break; } } while (!((serviceStatus.dwCurrentState == SERVICE_RUNNING) || (serviceStatus.dwCurrentState == SERVICE_STOPPED))); if (serviceStatus.dwCurrentState == SERVICE_RUNNING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s service resumed."), wrapperData->serviceDisplayName); } else { status = getNTServiceStatusName(serviceStatus.dwCurrentState); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT( "Failed to resume %s service. Status: %s"), wrapperData->serviceDisplayName, status); result = 1; } } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } /* Close this service object's handle to the service control manager */ CloseServiceHandle(schService); } else { if (GetLastError() == ERROR_ACCESS_DENIED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to resume the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); if (isVista() && !isElevated()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Performing this action requires that you run as an elevated process.")); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s service is not installed - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } result = 1; } /* Finally, close the handle to the service control manager's database */ CloseServiceHandle(schSCManager); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to resume the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } return result; } int sendServiceControlCodeInner(int controlCode) { SC_HANDLE schService; SC_HANDLE schSCManager; SERVICE_STATUS serviceStatus; TCHAR *status; int result = 0; /* First, get a handle to the service control manager */ schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (schSCManager) { /* Next get the handle to this service... */ schService = OpenService(schSCManager, wrapperData->serviceName, SERVICE_QUERY_STATUS | SERVICE_USER_DEFINED_CONTROL); if (schService) { /* Make sure that the service is in a state that can be resumed. */ if (QueryServiceStatus(schService, &serviceStatus)) { if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was not running."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_STOP_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of stopping."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_PAUSED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was currently paused."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_PAUSE_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of being paused."), wrapperData->serviceDisplayName); result = 1; } else if (serviceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s service was in the process of being resumed."), wrapperData->serviceDisplayName); } else { /* The service is running, so try sending the code. */ if (ControlService(schService, controlCode, &serviceStatus)) { result = 0; } else { status = getNTServiceStatusName(serviceStatus.dwCurrentState); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Attempt to send the %s service control code %d failed. Status: %s"), wrapperData->serviceDisplayName, controlCode, status); result = 1; } } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } /* Close this service object's handle to the service control manager */ CloseServiceHandle(schService); } else { if (GetLastError() == ERROR_ACCESS_DENIED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to send control code to the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("OpenService failed - %s"), getLastErrorText()); if (isVista() && !isElevated()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Performing this action requires that you run as an elevated process.")); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s service is not installed - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } result = 1; } /* Finally, close the handle to the service control manager's database */ CloseServiceHandle(schSCManager); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to send control code to the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } return result; } /** Sends a service control code to a running as an NT Service. */ int wrapperSendServiceControlCode(TCHAR **argv, TCHAR *controlCodeS) { int controlCode; int result; /* Make sure the control code is valid. */ if (controlCodeS == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Control code to send is missing.")); wrapperUsage(argv[0]); return 1; } controlCode = _ttoi(controlCodeS); if ((controlCode < 128) || (controlCode > 255)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The service control code must be in the range 128-255.")); return 1; } result = sendServiceControlCodeInner(controlCode); if (!result) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Sent the %s service control code %d."), wrapperData->serviceDisplayName, controlCode); } return result; } /** * Requests that the Wrapper perform a thread dump. */ int wrapperRequestThreadDump() { int result; if (wrapperData->threadDumpControlCode <= 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The thread dump control code is disabled.")); return 1; } result = sendServiceControlCodeInner(wrapperData->threadDumpControlCode); if (!result) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Requested that the %s service perform a thread dump."), wrapperData->serviceDisplayName); } return result; } /** * Obtains the current service status. * The returned result becomes the exitCode. The exitCode is made up of * a series of status bits: * * Bits: * 0: Service Installed. (1) * 1: Service Running. (2) * 2: Service Interactive. (4) * 3: Startup Mode: Auto. (8) * 4: Startup Mode: Manual. (16) * 5: Startup Mode: Disabled. (32) * 6: Service Running but Paused. (64) */ int wrapperServiceStatus(int consoleOutput) { SC_HANDLE schService; SC_HANDLE schSCManager; SERVICE_STATUS serviceStatus; QUERY_SERVICE_CONFIG *pQueryServiceConfig; DWORD reqSize; int result = 0; schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (schSCManager) { /* Next get the handle to this service... */ schService = OpenService(schSCManager, wrapperData->serviceName, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG); if (schService) { /* Service is installed, so set that bit. */ if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s Service is installed."), wrapperData->serviceDisplayName); } result |= 1; /* Get the service configuration. */ QueryServiceConfig(schService, NULL, 0, &reqSize); pQueryServiceConfig = malloc(reqSize); if (!pQueryServiceConfig) { outOfMemory(TEXT("WSS"), 1); CloseServiceHandle(schSCManager); return 0; } if (QueryServiceConfig(schService, pQueryServiceConfig, reqSize, &reqSize)) { switch (pQueryServiceConfig->dwStartType) { case SERVICE_BOOT_START: /* Possible? */ case SERVICE_SYSTEM_START: /* Possible? */ case SERVICE_AUTO_START: if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Start Type: Automatic")); } result |= 8; break; case SERVICE_DEMAND_START: if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Start Type: Manual")); } result |= 16; break; case SERVICE_DISABLED: if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Start Type: Disabled")); } result |= 32; break; default: if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT(" Start Type: Unknown")); } break; } if (pQueryServiceConfig->dwServiceType & SERVICE_INTERACTIVE_PROCESS) { /* This is an interactive service, so set that bit. */ if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Interactive: Yes")); } result |= 4; } else { if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Interactive: No")); } } free(pQueryServiceConfig); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the configuration of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } /* Find out what the current status of the service is so we can decide what to do. */ if (QueryServiceStatus(schService, &serviceStatus)) { if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { /* The service is stopped. */ if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Running: No")); } } else { /* Any other state, it is running. Set that bit. */ if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Running: Yes")); } result |= 2; if (serviceStatus.dwCurrentState == SERVICE_PAUSED) { if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Paused: Yes")); } result |= 64; } } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } /* Close this service object's handle to the service control manager */ CloseServiceHandle(schService); } else { if (GetLastError() == ERROR_ACCESS_DENIED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); if (isVista() && !isElevated()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Performing this action requires that you run as an elevated process.")); } } else { if (consoleOutput) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("The %s Service is not installed."), wrapperData->serviceDisplayName); } } } /* Finally, close the handle to the service control manager's database */ CloseServiceHandle(schSCManager); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to query the status of the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } return result; } /** * Uninstall the service and clean up */ int wrapperRemove() { SC_HANDLE schService; SC_HANDLE schSCManager; int result = 0; /* First attempt to stop the service if it is already running. */ result = wrapperStopService(FALSE); if (result) { /* There was a problem stopping the service. */ return result; } /* First, get a handle to the service control manager */ schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (schSCManager) { /* Next get the handle to this service... */ schService = OpenService(schSCManager, wrapperData->serviceName, SERVICE_QUERY_STATUS | DELETE); if (schService) { /* Now try to remove the service... */ if (DeleteService(schService)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("%s service removed."), wrapperData->serviceDisplayName); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to remove the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } /* Close this service object's handle to the service control manager */ CloseServiceHandle(schService); } else { if (GetLastError() == ERROR_ACCESS_DENIED) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to remove the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); if (isVista() && !isElevated()) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Performing this action requires that you run as an elevated process.")); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s service is not installed - %s"), wrapperData->serviceDisplayName, getLastErrorText()); } result = 1; } /* Finally, close the handle to the service control manager's database */ CloseServiceHandle(schSCManager); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to remove the %s service - %s"), wrapperData->serviceDisplayName, getLastErrorText()); result = 1; } /* Remove message file registration on service remove */ if (result == 0) { /* Do this here to unregister the syslog on uninstall of a resource. */ /* unregisterSyslogMessageFile(); */ } return result; } /** * Sets the working directory to that of the current executable */ int setWorkingDir() { int size = 128; TCHAR* szPath = NULL; DWORD usedLen; int result; TCHAR* pos; /* How large a buffer is needed? The GetModuleFileName function doesn't tell us how much * is needed, only if it is too short. */ do { szPath = malloc(sizeof(TCHAR) * size); if (!szPath) { outOfMemory(TEXT("SWD"), 1); return 1; } usedLen = GetModuleFileName(NULL, szPath, size); if (usedLen == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to get the path-%s"), getLastErrorText()); return 1; } else if ((usedLen == size) || (getLastError() == ERROR_INSUFFICIENT_BUFFER)) { /* Too small. */ size += 128; free(szPath); szPath = NULL; } } while (!szPath); /* The wrapperData->isDebugging flag will never be set here, so we can't really use it. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Executable Name: %s"), szPath); #endif /* To get the path, strip everything off after the last '\' */ pos = _tcsrchr(szPath, TEXT('\\')); if (pos == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to extract path from: %s"), szPath); free(szPath); return 1; } else { /* Clip the path at the position of the last backslash */ pos[0] = (TCHAR)0; } /* Set a variable to the location of the binary. */ setEnv(TEXT("WRAPPER_BIN_DIR"), szPath, ENV_SOURCE_APPLICATION); result = wrapperSetWorkingDir(szPath, TRUE); free(szPath); return result; } /****************************************************************************** * Main function *****************************************************************************/ /** Attempts to resolve the name of an exception. Returns null if it is unknown. */ TCHAR* getExceptionName(DWORD exCode) { TCHAR *exName; switch (exCode) { case EXCEPTION_ACCESS_VIOLATION: exName = TEXT("EXCEPTION_ACCESS_VIOLATION"); break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: exName = TEXT("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); break; case EXCEPTION_BREAKPOINT: exName = TEXT("EXCEPTION_BREAKPOINT"); break; case EXCEPTION_DATATYPE_MISALIGNMENT: exName = TEXT("EXCEPTION_DATATYPE_MISALIGNMENT"); break; case EXCEPTION_FLT_DENORMAL_OPERAND: exName = TEXT("EXCEPTION_FLT_DENORMAL_OPERAND"); break; case EXCEPTION_FLT_DIVIDE_BY_ZERO: exName = TEXT("EXCEPTION_FLT_DIVIDE_BY_ZERO"); break; case EXCEPTION_FLT_INEXACT_RESULT: exName = TEXT("EXCEPTION_FLT_INEXACT_RESULT"); break; case EXCEPTION_FLT_INVALID_OPERATION: exName = TEXT("EXCEPTION_FLT_INVALID_OPERATION"); break; case EXCEPTION_FLT_OVERFLOW: exName = TEXT("EXCEPTION_FLT_OVERFLOW"); break; case EXCEPTION_FLT_STACK_CHECK: exName = TEXT("EXCEPTION_FLT_STACK_CHECK"); break; case EXCEPTION_FLT_UNDERFLOW: exName = TEXT("EXCEPTION_FLT_UNDERFLOW"); break; case EXCEPTION_ILLEGAL_INSTRUCTION: exName = TEXT("EXCEPTION_ILLEGAL_INSTRUCTION"); break; case EXCEPTION_IN_PAGE_ERROR: exName = TEXT("EXCEPTION_IN_PAGE_ERROR"); break; case EXCEPTION_INT_DIVIDE_BY_ZERO: exName = TEXT("EXCEPTION_INT_DIVIDE_BY_ZERO"); break; case EXCEPTION_INT_OVERFLOW: exName = TEXT("EXCEPTION_INT_OVERFLOW"); break; case EXCEPTION_INVALID_DISPOSITION: exName = TEXT("EXCEPTION_INVALID_DISPOSITION"); break; case EXCEPTION_NONCONTINUABLE_EXCEPTION: exName = TEXT("EXCEPTION_NONCONTINUABLE_EXCEPTION"); break; case EXCEPTION_PRIV_INSTRUCTION: exName = TEXT("EXCEPTION_PRIV_INSTRUCTION"); break; case EXCEPTION_SINGLE_STEP: exName = TEXT("EXCEPTION_SINGLE_STEP"); break; case EXCEPTION_STACK_OVERFLOW: exName = TEXT("EXCEPTION_STACK_OVERFLOW"); break; default: exName = NULL; break; } return exName; } /** * Logs some dump information to the log output and then generate a minidump file. */ int exceptionFilterFunction(PEXCEPTION_POINTERS exceptionPointers) { DWORD exCode; TCHAR *exName; int i; size_t len; TCHAR curDir[MAX_PATH]; TCHAR dumpFile[MAX_PATH]; BOOL dumpSuccessful; HANDLE hDumpFile; SYSTEMTIME stLocalTime; MINIDUMP_EXCEPTION_INFORMATION expParam; int couldLoad; FARPROC miniDumpWriteDumpDyn; HMODULE dbgHelpDll = LoadLibrary(TEXT("Dbghelp.dll")); if( dbgHelpDll == NULL) { couldLoad = FALSE; } else { miniDumpWriteDumpDyn = GetProcAddress(dbgHelpDll, "MiniDumpWriteDump"); if(miniDumpWriteDumpDyn == NULL) { couldLoad = FALSE; } else { couldLoad = TRUE; } } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("--------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("encountered a fatal error in Wrapper")); exCode = exceptionPointers->ExceptionRecord->ExceptionCode; exName = getExceptionName(exCode); if (exName == NULL) { exName = malloc(sizeof(TCHAR) * 64); /* Let this leak. It only happens once before shutdown. */ if (exName) { _sntprintf(exName, 64, TEXT("Unknown Exception (%ld)"), exCode); } } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" exceptionCode = %s"), exName); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" exceptionFlag = %s"), (exceptionPointers->ExceptionRecord->ExceptionFlags == EXCEPTION_NONCONTINUABLE ? TEXT("EXCEPTION_NONCONTINUABLE") : TEXT("EXCEPTION_NONCONTINUABLE_EXCEPTION"))); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" exceptionAddress = %p"), exceptionPointers->ExceptionRecord->ExceptionAddress); if (exCode == EXCEPTION_ACCESS_VIOLATION) { if (exceptionPointers->ExceptionRecord->ExceptionInformation[0] == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Read access exception from %p"), exceptionPointers->ExceptionRecord->ExceptionInformation[1]); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Write access exception to %p"), exceptionPointers->ExceptionRecord->ExceptionInformation[1]); } } else { for (i = 0; i < (int)exceptionPointers->ExceptionRecord->NumberParameters; i++) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" exceptionInformation[%d] = %ld"), i, exceptionPointers->ExceptionRecord->ExceptionInformation[i]); } } if (wrapperData) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Wrapper Main Loop Status:")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Current Ticks: 0x%08x"), wrapperGetTicks()); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Wrapper State: %s"), wrapperGetWState(wrapperData->wState)); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Java State: %s (Timeout: 0x%08x)"), wrapperGetJState(wrapperData->jState), wrapperData->jStateTimeoutTicks); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Exit Requested: %s"), (wrapperData->exitRequested ? TEXT("true") : TEXT("false"))); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Restart Mode: %d"), wrapperData->restartRequested); } /* Get the current directory. */ len = GetCurrentDirectory(MAX_PATH, curDir); if (len == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Unable to request current directory. %s"), getLastErrorText()); _sntprintf(curDir, MAX_PATH, TEXT(".")); } /* Generate the minidump. */ GetLocalTime(&stLocalTime); _sntprintf(dumpFile, MAX_PATH, TEXT("wrapper-%s-%s-%s-%s-%04d%02d%02d%02d%02d%02d-%ld-%ld.dmp"), wrapperOS, wrapperArch, wrapperBits, wrapperVersion, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, GetCurrentProcessId(), GetCurrentThreadId()); if (couldLoad == TRUE) { hDumpFile = CreateFile(dumpFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); if (hDumpFile == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Failed to create dump file:\n %s\\%s : %s"), curDir, dumpFile, getLastErrorText()); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Writing dump file: %s\\%s"), curDir, dumpFile); expParam.ThreadId = GetCurrentThreadId(); expParam.ExceptionPointers = exceptionPointers; expParam.ClientPointers = TRUE; dumpSuccessful = (BOOL)miniDumpWriteDumpDyn(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpWithDataSegs, &expParam, NULL, NULL); FreeLibrary(dbgHelpDll); if (dumpSuccessful) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Dump completed.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Please send the dump file to support@tanukisoftware.com along with\n your wrapper.conf and wrapper.log files.")); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Failed to generate dump file. %s"), getLastErrorText()); } } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" Please send the log file to support@tanukisoftware.com along with\n your wrapper.conf file.")); } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("--------------------------------------------------------------------") ); return EXCEPTION_EXECUTE_HANDLER; } LPWSTR AllocateAndCopyWideString(LPCWSTR inputString) { LPWSTR outputString = NULL; outputString = (LPWSTR)LocalAlloc(LPTR, (wcslen(inputString) + 1) * sizeof(WCHAR)); if (outputString != NULL) { lstrcpyW(outputString, inputString); } return outputString; } BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, PSPROG_PUBLISHERINFO Info) { DWORD n; BOOL fReturn = FALSE; PSPC_SP_OPUS_INFO OpusInfo = NULL; DWORD dwData; BOOL fResult; __try { /* Loop through authenticated attributes and find SPC_SP_OPUS_INFO_OBJID OID. */ for (n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++) { if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0) { /* Get Size of SPC_SP_OPUS_INFO structure. */ fResult = CryptDecodeObject(ENCODING, SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 0, NULL, &dwData); if (!fResult) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CryptDecodeObject failed with %x"), GetLastError()); __leave; } /* Allocate memory for SPC_SP_OPUS_INFO structure. */ OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData); if (!OpusInfo) { outOfMemory(TEXT("GPAPI"), 1); __leave; } /* Decode and get SPC_SP_OPUS_INFO structure. */ fResult = CryptDecodeObject(ENCODING, SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 0, OpusInfo, &dwData); if (!fResult) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CryptDecodeObject failed with %x"), GetLastError()); __leave; } /* Fill in Program Name if present. */ if (OpusInfo->pwszProgramName) { Info->lpszProgramName = AllocateAndCopyWideString(OpusInfo->pwszProgramName); } else { Info->lpszProgramName = NULL; } /* Fill in Publisher Information if present. */ if (OpusInfo->pPublisherInfo) { switch (OpusInfo->pPublisherInfo->dwLinkChoice) { case SPC_URL_LINK_CHOICE: Info->lpszPublisherLink = AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl); break; case SPC_FILE_LINK_CHOICE: Info->lpszPublisherLink = AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile); break; default: Info->lpszPublisherLink = NULL; break; } } else { Info->lpszPublisherLink = NULL; } /* Fill in More Info if present. */ if (OpusInfo->pMoreInfo) { switch (OpusInfo->pMoreInfo->dwLinkChoice) { case SPC_URL_LINK_CHOICE: Info->lpszMoreInfoLink = AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl); break; case SPC_FILE_LINK_CHOICE: Info->lpszMoreInfoLink = AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile); break; default: Info->lpszMoreInfoLink = NULL; break; } } else { Info->lpszMoreInfoLink = NULL; } fReturn = TRUE; break; /* Break from for loop. */ } /* lstrcmp SPC_SP_OPUS_INFO_OBJID */ } /* for */ } __finally { if (OpusInfo != NULL) LocalFree(OpusInfo); } return fReturn; } BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st) { BOOL fResult; FILETIME lft, ft; DWORD dwData; BOOL fReturn = FALSE; DWORD n; /* Loop through authenticated attributes and find szOID_RSA_signingTime OID. */ for (n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++) { if (lstrcmpA(szOID_RSA_signingTime, pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0) { /* Decode and get FILETIME structure. */ dwData = sizeof(ft); fResult = CryptDecodeObject(ENCODING, szOID_RSA_signingTime, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 0, (PVOID)&ft, &dwData); if (!fResult) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CryptDecodeObject failed with %x"), GetLastError()); break; } /* Convert to local time. */ FileTimeToLocalFileTime(&ft, &lft); FileTimeToSystemTime(&lft, st); fReturn = TRUE; break; /* Break from for loop. */ } /* lstrcmp szOID_RSA_signingTime */ } /* for */ return fReturn; } BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, PCMSG_SIGNER_INFO *pCounterSignerInfo) { PCCERT_CONTEXT pCertContext = NULL; BOOL fReturn = FALSE; BOOL fResult; DWORD dwSize, n; __try { *pCounterSignerInfo = NULL; /* Loop through unathenticated attributes for szOID_RSA_counterSign OID. */ for (n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++) { if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RSA_counterSign) == 0) { /* Get size of CMSG_SIGNER_INFO structure. */ fResult = CryptDecodeObject(ENCODING, PKCS7_SIGNER_INFO, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, 0, NULL, &dwSize); if (!fResult) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CryptDecodeObject failed with %x"), GetLastError()); __leave; } /* Allocate memory for CMSG_SIGNER_INFO. */ *pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize); if (!*pCounterSignerInfo) { outOfMemory(TEXT("GTSSI"), 1); __leave; } /* Decode and get CMSG_SIGNER_INFO structure for timestamp certificate. */ fResult = CryptDecodeObject(ENCODING, PKCS7_SIGNER_INFO, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, 0, (PVOID)*pCounterSignerInfo, &dwSize); if (!fResult) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CryptDecodeObject failed with %x"), GetLastError()); __leave; } fReturn = TRUE; break; /* Break from for loop. */ } } } __finally { /* Clean up.*/ if (pCertContext != NULL) CertFreeCertificateContext(pCertContext); } return fReturn; } LPTSTR PrintCertificateInfo(PCCERT_CONTEXT pCertContext, int level) { BOOL fReturn = FALSE; LPTSTR szName1 = NULL; LPTSTR szName2 = NULL; LPTSTR serialNr = NULL; DWORD dwData, serialNrLength = 0, n, i; LPTSTR buffer = NULL; size_t size = 0; __try { /* Print Serial Number. */ //log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" Serial Number: ")); dwData = pCertContext->pCertInfo->SerialNumber.cbData; for (i = 0; i < 2; i++) { for (n = 0; n < dwData; n++) { if (serialNr) { _sntprintf(serialNr + (n * 3) , serialNrLength - (n * 3), TEXT("%02x "), pCertContext->pCertInfo->SerialNumber.pbData[dwData - (n + 1)]); } else { serialNrLength += 3; } } if (!serialNr) { serialNr = calloc(serialNrLength + 1, sizeof(TCHAR)); if (!serialNr) { outOfMemory(TEXT("PCI"), 1); __leave; } } } //log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" %s"), serialNr); /* Get Issuer name size. */ if (!(dwData = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0))) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CertGetNameString failed.")); __leave; } /* Allocate memory for Issuer name. */ szName1 = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR)); if (!szName1) { outOfMemory(TEXT("PCI"), 2); __leave; } /* Get Issuer name. */ if (!(CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, szName1, dwData))) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CertGetNameString failed.")); __leave; } /* print Issuer name. */ // log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" Issuer Name: %s"), szName1); /* Get Subject name size. */ if (!(dwData = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0))) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CertGetNameString failed.")); __leave; } /* Allocate memory for subject name. */ szName2 = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR)); if (!szName2) { outOfMemory(TEXT("GTSSI"), 3); __leave; } /* Get subject name. */ if (!(CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, szName2, dwData))) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CertGetNameString failed.")); __leave; } size = _tcslen(TEXT(" Serial Number: ")) + dwData * 3 + 6 + _tcslen(TEXT(" Issuer Name: ")) + _tcslen(TEXT(" Subject Name: ")) + _tcslen(szName1) + _tcslen(szName2) + 5; buffer = calloc(size, sizeof(TCHAR)); if (!buffer) { outOfMemory(TEXT("GTSSI"), 4); __leave; } _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" Serial Number: ")); _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT("\n %s\n"), serialNr); _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" Issuer Name: %s"), szName1); _tcsncat(buffer, TEXT("\n"), size - _tcslen(buffer)); _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" Subject Name: %s"), szName2); } __finally { if (szName1 != NULL) LocalFree(szName1); if (szName2 != NULL) LocalFree(szName2); if (serialNr != NULL) free(serialNr); } return buffer; } LPTSTR printWholeCertificateInfo(LPCWSTR wrapperExeName, int level) { HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; PCCERT_CONTEXT pCertContext = NULL; BOOL fResult; DWORD dwEncoding, dwContentType, dwFormatType; PCMSG_SIGNER_INFO pSignerInfo = NULL; PCMSG_SIGNER_INFO pCounterSignerInfo = NULL; DWORD dwSignerInfo; CERT_INFO CertInfo; SPROG_PUBLISHERINFO ProgPubInfo; SYSTEMTIME st; LPTSTR string1 = NULL; LPTSTR string2 = NULL; LPTSTR buffer = NULL; size_t size = 0; DWORD programSet = FALSE; DWORD publisherSet = FALSE; DWORD moreSet = FALSE; DWORD dateSet = FALSE; DWORD getTimeSignerSet = FALSE; DWORD getProgAndPublisherInfoSet = FALSE; ZeroMemory(&ProgPubInfo, sizeof(ProgPubInfo)); __try { /* Get message handle and store handle from the signed file. */ fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE, wrapperExeName, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL); if (!fResult) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("No certificate found! Error: %x"), GetLastError()); __leave; } /* Get signer information size. */ fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo); if (!fResult) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CryptMsgGetParam failed with %x"), GetLastError()); __leave; } /* Allocate memory for signer information. */ pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo); if (!pSignerInfo) { outOfMemory(TEXT("GWCI"), 1); __leave; } /* Get Signer Information. */ fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo, &dwSignerInfo); if (!fResult) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CryptMsgGetParam failed with %x"), GetLastError()); __leave; } /* Get program name and publisher information from signer info structure. */ if (GetProgAndPublisherInfo(pSignerInfo, &ProgPubInfo)) { getProgAndPublisherInfoSet = TRUE; if (ProgPubInfo.lpszProgramName != NULL) { size += _tcslen(TEXT(" Program Name : ")) + _tcslen(ProgPubInfo.lpszProgramName) + 1; programSet = TRUE; //log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" Program Name : %s"), // ProgPubInfo.lpszProgramName); } if (ProgPubInfo.lpszPublisherLink != NULL) { size += _tcslen(TEXT(" Publisher Link : ")) + _tcslen(ProgPubInfo.lpszPublisherLink) + 1; publisherSet = TRUE; // log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" Publisher Link : %s"), // ProgPubInfo.lpszPublisherLink); } if (ProgPubInfo.lpszMoreInfoLink != NULL) { moreSet = TRUE; size += _tcslen(TEXT(" MoreInfo Link : ")) + _tcslen(ProgPubInfo.lpszMoreInfoLink) + 1; // log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" MoreInfo Link : %s"), // ProgPubInfo.lpszMoreInfoLink); } } /* Search for the signer certificate in the temporary certificate store. */ CertInfo.Issuer = pSignerInfo->Issuer; CertInfo.SerialNumber = pSignerInfo->SerialNumber; pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL); if (!pCertContext) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CertFindCertificateInStore failed with %x"), GetLastError()); __leave; } /* Print Signer certificate information. */ //log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" Signer Certificate:")); string1 = PrintCertificateInfo(pCertContext, level); size += _tcslen(TEXT(" Signer Certificate:")) + _tcslen(string1) + 2; /* Get the timestamp certificate signerinfo structure. */ if (GetTimeStampSignerInfo(pSignerInfo, &pCounterSignerInfo)) { getTimeSignerSet = TRUE; /* Search for Timestamp certificate in the temporary certificate store. */ CertInfo.Issuer = pCounterSignerInfo->Issuer; CertInfo.SerialNumber = pCounterSignerInfo->SerialNumber; pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL); if (!pCertContext) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CertFindCertificateInStore failed with %x"), GetLastError()); __leave; } /* Print timestamp certificate information. */ //log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" TimeStamp Certificate:")); string2 = PrintCertificateInfo(pCertContext, level); size += _tcslen(TEXT(" TimeStamp Certificate:")) + _tcslen(string2) + 2; /* Find Date of timestamp. */ if (GetDateOfTimeStamp(pCounterSignerInfo, &st)) { size += _tcslen( TEXT(" Date of TimeStamp : %04d/%02d/%02d %02d:%02d")) - 8 + 1; dateSet = FALSE; //log_printf(WRAPPER_SOURCE_WRAPPER, level, TEXT(" Date of TimeStamp : %04d/%02d/%02d %02d:%02d"), // st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute); } } /* increment size for hodling \0 */ size++; buffer = calloc(size, sizeof(TCHAR)); if (!buffer) { outOfMemory(TEXT("GWCI"), 2); __leave; } if (getProgAndPublisherInfoSet) { if (programSet) { _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" Program Name : %s"), ProgPubInfo.lpszProgramName); _tcsncat(buffer, TEXT("\n"), size - _tcslen(buffer)); } if (publisherSet) { _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" Publisher Link : %s"), ProgPubInfo.lpszPublisherLink); _tcsncat(buffer, TEXT("\n"), size - _tcslen(buffer)); } if (publisherSet) { _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" MoreInfo Link : %s"), ProgPubInfo.lpszMoreInfoLink); _tcsncat(buffer, TEXT("\n"), size - _tcslen(buffer)); } } _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" Signer Certificate:")); _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT("\n%s\n"), string1); if (getTimeSignerSet) { _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" TimeStamp Certificate:")); _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT("\n%s\n"), string2); } if (dateSet) { _sntprintf(buffer + _tcslen(buffer), size - _tcslen(buffer), TEXT(" Date of TimeStamp : %04d/%02d/%02d %02d:%02d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute); } buffer[size - 1] = TEXT('\0'); } __finally { /* Clean up. */ if (ProgPubInfo.lpszProgramName != NULL) { LocalFree(ProgPubInfo.lpszProgramName); } if (ProgPubInfo.lpszPublisherLink != NULL) { LocalFree(ProgPubInfo.lpszPublisherLink); } if (ProgPubInfo.lpszMoreInfoLink != NULL) { LocalFree(ProgPubInfo.lpszMoreInfoLink); } if (pSignerInfo != NULL) { LocalFree(pSignerInfo); } if (pCounterSignerInfo != NULL) { LocalFree(pCounterSignerInfo); } if (pCertContext != NULL) { CertFreeCertificateContext(pCertContext); } if (hStore != NULL) { CertCloseStore(hStore, 0); } if (hMsg != NULL) { CryptMsgClose(hMsg); } if (string1 != NULL) { free(string1); } if (string2 != NULL) { free(string2); } } return buffer; } BOOL verifyEmbeddedSignature() { LONG lStatus; DWORD dwLastError; const TCHAR* lastErrMsg; TCHAR pwszSourceFile[_MAX_PATH]; GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2; WINTRUST_DATA WinTrustData; WINTRUST_FILE_INFO FileData; LPTSTR buffer = NULL; if (!GetModuleFileName(NULL, pwszSourceFile, _MAX_PATH)) { return FALSE; } memset(&FileData, 0, sizeof(FileData)); FileData.cbStruct = sizeof(WINTRUST_FILE_INFO); FileData.pcwszFilePath = pwszSourceFile; FileData.hFile = NULL; FileData.pgKnownSubject = NULL; memset(&WinTrustData, 0, sizeof(WinTrustData)); WinTrustData.cbStruct = sizeof(WinTrustData); WinTrustData.pPolicyCallbackData = NULL; WinTrustData.pSIPClientData = NULL; WinTrustData.dwUIChoice = WTD_UI_NONE; WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE; WinTrustData.dwUnionChoice = WTD_CHOICE_FILE; WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY; WinTrustData.hWVTStateData = NULL; WinTrustData.pwszURLReference = NULL; WinTrustData.dwProvFlags = WTD_USE_DEFAULT_OSVER_CHECK; WinTrustData.dwUIContext = 0; WinTrustData.pFile = &FileData; lStatus = WinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData); switch (lStatus) { case ERROR_SUCCESS: buffer = printWholeCertificateInfo(pwszSourceFile, LEVEL_DEBUG); if (buffer) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The file \"%s\" is signed and the signature was verified.\n%s"), pwszSourceFile, buffer); free(buffer); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The file \"%s\" is signed and the signature was verified."), pwszSourceFile); } break; case TRUST_E_NOSIGNATURE: /* The file was not signed or had a signature that was not valid. */ /* Get the reason for no signature. */ dwLastError = GetLastError(); if ((TRUST_E_SUBJECT_FORM_UNKNOWN == dwLastError) || (TRUST_E_NOSIGNATURE == dwLastError) || (TRUST_E_PROVIDER_UNKNOWN == dwLastError)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("The file \"%s\" is not signed."), pwszSourceFile); } else { /* The signature was not valid or there was an error opening the file. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("An unknown error occurred trying to verify the signature of the \"%s\" file: %s"), pwszSourceFile, getLastErrorText()); } break; case TRUST_E_EXPLICIT_DISTRUST: /* The hash that represents the subject or the publisher is not allowed by the admin or user. */ buffer = printWholeCertificateInfo(pwszSourceFile, LEVEL_WARN); if (buffer) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The signature is present, but specifically disallowed.\n%s\nThe Wrapper will shutdown!"), buffer); free(buffer); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The signature is present, but specifically disallowed.\nThe Wrapper will shutdown!")); } appExit(0); break; case TRUST_E_SUBJECT_NOT_TRUSTED: /* The user clicked "No" when asked to install and run. */ buffer = printWholeCertificateInfo(pwszSourceFile, LEVEL_WARN); if (buffer) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The signature is present, but not trusted.\n%s"), buffer); free(buffer); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The signature is present, but not trusted.")); } break; case CRYPT_E_SECURITY_SETTINGS: /* The hash that represents the subject or the publisher was not explicitly trusted by the admin and the admin policy has disabled user trust. No signature, publisher or time stamp errors. */ buffer = printWholeCertificateInfo(pwszSourceFile, LEVEL_WARN); if (buffer) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CRYPT_E_SECURITY_SETTINGS - The hash\nrepresenting the subject or the publisher wasn't\nexplicitly trusted by the admin and admin policy\nhas disabled user trust. No signature, publisher or timestamp errors.\n%s"), buffer); free(buffer); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("CRYPT_E_SECURITY_SETTINGS - The hash\nrepresenting the subject or the publisher wasn't\nexplicitly trusted by the admin and admin policy\nhas disabled user trust. No signature, publisher or timestamp errors.")); } break; default: dwLastError = GetLastError(); lastErrMsg = getLastErrorText(); buffer = printWholeCertificateInfo(pwszSourceFile, LEVEL_WARN); if (buffer) { if (dwLastError == TRUST_E_BAD_DIGEST || dwLastError == TRUST_E_CERT_SIGNATURE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("A signature was found in \"%s\", but checksum failed: (Errorcode: 0x%x) %s\n%s\nThe Wrapper will shutdown!"), pwszSourceFile, lStatus, lastErrMsg, buffer); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("A signature was found in \"%s\", but checksum failed: (Errorcode: 0x%x) %s\n%sThe error is not directly related to the Wrapper's signature, therefore continue..."), pwszSourceFile, lStatus, lastErrMsg, buffer); } } else { if (dwLastError == TRUST_E_BAD_DIGEST || dwLastError == TRUST_E_CERT_SIGNATURE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("A signature was found in \"%s\", but checksum failed: (Errorcode: 0x%x) %s\nThe Wrapper will shutdown!"), pwszSourceFile, lStatus, lastErrMsg); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("A signature was found in \"%s\", but checksum failed: (Errorcode: 0x%x) %s\nThe error is not directly related to the Wrapper's signature, therefore continue..."), pwszSourceFile, lStatus, lastErrMsg); } } if (dwLastError == TRUST_E_BAD_DIGEST || dwLastError == TRUST_E_CERT_SIGNATURE) { wrapperStopProcess(1, TRUE); wrapperData->wState = WRAPPER_WSTATE_STOPPING; } break; } return TRUE; } /** * Does some special setup for when we are running as a launcher. */ void enterLauncherMode() { /* Tell the logger to use the launcher source in place of the actual one so it is clear those entries are coming from the launcher and not the actual service. */ setLauncherSource(); } #ifndef CUNIT void _tmain(int argc, TCHAR **argv) { int result; #ifdef _DEBUG int i; #endif /* The StartServiceCtrlDispatcher requires this table to specify * the ServiceMain function to run in the calling process. The first * member in this example is actually ignored, since we will install * our service as a SERVICE_WIN32_OWN_PROCESS service type. The NULL * members of the last entry are necessary to indicate the end of * the table; */ SERVICE_TABLE_ENTRY serviceTable[2]; if (buildSystemPath()) { appExit(1); return; /* For clarity. */ } if (wrapperInitialize()) { appExit(1); return; /* For clarity. */ } SetThreadLocale(GetUserDefaultLCID()); /* Main thread initialized in wrapperInitialize. */ /* Enclose the rest of the program in a try catch block so we can * display and log useful information should the need arise. This * must be done after logging has been initialized as the catch * block makes use of the logger. */ __try { #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Wrapper DEBUG build!")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Logging initialized.")); #endif /* Get the current process. */ wrapperData->wrapperProcess = GetCurrentProcess(); wrapperData->wrapperPID = GetCurrentProcessId(); if (initializeWinSock()) { appExit(1); return; /* For clarity. */ } if (setWorkingDir()) { appExit(1); return; /* For clarity. */ } if (collectUserInfo()) { appExit(1); return; /* For clarity. */ } #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Working directory set.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Arguments:")); for (i = 0; i < argc; i++) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" argv[%d]=%s"), i, argv[i]); } #endif /* Parse the command and configuration file from the command line. */ if (!wrapperParseArguments(argc, argv)) { appExit(1); return; /* For clarity. */ } wrapperLoadHostName(); /* At this point, we have a command, confFile, and possibly additional arguments. */ if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("?")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-help"))) { /* User asked for the usage. */ setSimpleLogLevels(); wrapperUsage(argv[0]); appExit(0); return; /* For clarity. */ } else if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("v")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-version"))) { /* User asked for version. */ setSimpleLogLevels(); wrapperVersionBanner(); appExit(0); return; /* For clarity. */ } else if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("h")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-hostid"))) { /* Print out a banner containing the host id. */ setSimpleLogLevels(); wrapperVersionBanner(); showHostIds(LEVEL_STATUS); appExit(0); return; /* For clarity. */ } /* All 4 valid commands use the configuration file. It is loaded here to * reduce duplicate code. But before loading the parameters, in the case * of an NT service. the environment variables must first be loaded from * the registry. * This is not necessary for versions of Windows XP and above. */ if ((!strcmpIgnoreCase(wrapperData->argCommand, TEXT("s")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-service"))) && (isVista() == FALSE)) { if (wrapperLoadEnvFromRegistry()) { appExit(1); return; /* For clarity. */ } } /* Load the properties. */ if (wrapperLoadConfigurationProperties(FALSE)) { /* Unable to load the configuration. Any errors will have already * been reported. */ if (wrapperData->argConfFileDefault && !wrapperData->argConfFileFound) { /* The config file that was being looked for was default and * it did not exist. Show the usage. */ wrapperUsage(argv[0]); } appExit(1); return; /* For clarity. */ } /* Set the default umask of the Wrapper process. */ _umask(wrapperData->umask); /* Perform the specified command */ if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("i")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-install"))) { /* Install an NT service */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); wrapperCheckForMappedDrives(); /* are we elevated ? */ if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperInstall()); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("it")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-installstart"))) { /* Install and Start an NT service */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); wrapperCheckForMappedDrives(); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } result = wrapperInstall(); if (!result) { result = wrapperStartService(); } appExit(result); } return; /* For clarity. */ } else if (!strcmpIgnoreCase(wrapperData->argCommand, TEXT("r")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-remove"))) { /* Remove an NT service */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperRemove()); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("t")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-start"))) { /* Start an NT service */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); wrapperCheckForMappedDrives(); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperStartService()); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("a")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-pause"))) { /* Pause a started NT service */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperPauseService()); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("e")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-resume"))) { /* Resume a paused NT service */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperResumeService()); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("p")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-stop"))) { /* Stop an NT service */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperStopService(TRUE)); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("l")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-controlcode"))) { /* Send a control code to an NT service */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperSendServiceControlCode(argv, wrapperData->argCommandArg)); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("d")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-dump"))) { /* Request a thread dump */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperRequestThreadDump(argv)); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("q")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-query"))) { /* Return service status with console output. */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperServiceStatus(TRUE)); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("qs")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-querysilent"))) { /* Return service status without console output. */ enterLauncherMode(); /* Always auto close the log file to keep the output in synch. */ setLogfileAutoClose(TRUE); if (!isElevated()) { appExit(elevateThis(argc, argv)); } else { /* are we launched secondary? */ if (getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL) != NULL && duplicateSTD() == FALSE) { appExit(1); return; } appExit(wrapperServiceStatus(FALSE)); } return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("c")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-console"))) { /* Run as a console application */ /* Load any dynamic functions. */ loadDLLProcs(); /* Initialize the invocation mutex as necessary, exit if it already exists. */ if (initInvocationMutex()) { appExit(1); return; /* For clarity. */ } /* See if the logs should be rolled on Wrapper startup. */ if ((getLogfileRollMode() & ROLL_MODE_WRAPPER) || (getLogfileRollMode() & ROLL_MODE_JVM)) { rollLogs(); } cleanUpPIDFilesOnExit = TRUE; if (wrapperData->pidFilename) { if (writePidFile(wrapperData->pidFilename, wrapperData->wrapperPID, wrapperData->pidFileUmask, wrapperData->pidFileStrict)) { log_printf (WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not write pid file %s: %s"), wrapperData->pidFilename, getLastErrorText()); appExit(1); return; /* For clarity. */ } } /* Write pid and anchor files as requested. If they are the same file the file is * simply overwritten. */ if (wrapperData->anchorFilename) { if (writePidFile(wrapperData->anchorFilename, wrapperData->wrapperPID, wrapperData->anchorFileUmask, FALSE)) { log_printf (WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not write anchor file %s: %s"), wrapperData->anchorFilename, getLastErrorText()); appExit(1); return; /* For clarity. */ } } if (wrapperData->lockFilename) { if (writePidFile(wrapperData->lockFilename, wrapperData->wrapperPID, wrapperData->lockFileUmask, FALSE)) { log_printf (WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not write lock file %s: %s"), wrapperData->lockFilename, getLastErrorText()); appExit(1); return; /* For clarity. */ } } appExit(wrapperRunConsole()); return; /* For clarity. */ } else if(!strcmpIgnoreCase(wrapperData->argCommand, TEXT("s")) || !strcmpIgnoreCase(wrapperData->argCommand, TEXT("-service"))) { /* Run as a service */ wrapperData->isConsole = FALSE; wrapperCheckForMappedDrives(); /* Load any dynamic functions. */ loadDLLProcs(); /* Prepare the service table */ serviceTable[0].lpServiceName = wrapperData->serviceName; serviceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)wrapperServiceMain; serviceTable[1].lpServiceName = NULL; serviceTable[1].lpServiceProc = NULL; _tprintf(TEXT("Attempting to start %s as an NT service.\n"), wrapperData->serviceDisplayName); _tprintf(TEXT("\nCalling StartServiceCtrlDispatcher...please wait.\n")); /* Start the service control dispatcher. * The ServiceControlDispatcher will call the wrapperServiceMain method. */ if (!StartServiceCtrlDispatcher(serviceTable)) { _tprintf(TEXT("\n")); _tprintf(TEXT("StartServiceControlDispatcher failed!\n")); _tprintf(TEXT("\n")); _tprintf(TEXT("The -s and --service commands should only be called by the Windows\n")); _tprintf(TEXT("ServiceManager to control the Wrapper as a service, and is not\n")); _tprintf(TEXT("designed to be run manually by the user.\n")); _tprintf(TEXT("\n")); _tprintf(TEXT("For help, type\n")); _tprintf(TEXT("%s -?\n"), argv[0]); _tprintf(TEXT("\n")); appExit(1); return; /* For clarity. */ } /* We will get here when the service starts to stop */ /* As wrapperServiceMain should take care of shutdown, wait 10 sec to give some time for its shutdown * but the process should exit before the sleep completes. */ wrapperSleep(10000); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Timed out waiting for wrapperServiceMain")); appExit(1); return; /* For clarity. */ } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unrecognized option: -%s"), wrapperData->argCommand); wrapperUsage(argv[0]); appExit(1); return; /* For clarity. */ } } __except (exceptionFilterFunction(GetExceptionInformation())) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("<-- Wrapper Stopping due to error")); appExit(1); return; /* For clarity. */ } } #endif /* * This function will connect to the secondary/elevated wrapper process and * read all output from stdout and stderr. Furthermore it will handle input * being sent to stdin. This function won't return until the client closed all * named pipes connected. * @param in - the File HANDLE for the outbound channel to write to the 2nd process * @param out, err - the File HANDLEs for the inbound channel to read from the 2nd process * * @return TRUE if everything worked well. FALSE otherwise. */ BOOL readAndWriteNamedPipes(HANDLE in, HANDLE out, HANDLE err) { TCHAR inbuf[1024], outbuf[512], errbuf[512], *secret; DWORD currentBlockAvail, outRead, errRead, inWritten, ret, writeOut; BOOL fConnected, outClosed = FALSE, errClosed = FALSE; /* the named pipes are nonblocking, so loop until an connection could * have been established with the secondary process (or an error occured) */ do { /* ConnectNamedPipe does rather wait until a connection was established However, the inbound pipes are non-blocking, so ConnectNamedPipe immediately returns. So call it looped...*/ fConnected = ConnectNamedPipe(out, NULL); } while((fConnected == 0) && (GetLastError() == ERROR_PIPE_LISTENING)); /* check for error */ /* if ERROR_PIPE_CONNECTED it just means that while ConnectNamedPipe(..) was * called again, in the meantime the client connected. So in fact that's what we want. * WIN-7: if ERROR_NO_DATA, it means that the process has already been gone, probably an error in the start (but not in the pipe) * it might even be very likely there is data in stderr to retrieve */ if ((fConnected == 0) && (GetLastError() != ERROR_PIPE_CONNECTED) && (GetLastError() != ERROR_NO_DATA)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("The connect to stdout of the elevated process failed: %s"), getLastErrorText()); return FALSE; } /* Same as above */ do { fConnected = ConnectNamedPipe(err, NULL); } while((fConnected == 0) && (GetLastError() == ERROR_PIPE_LISTENING)); if ((fConnected == 0) && (GetLastError() != ERROR_PIPE_CONNECTED) && (GetLastError() != ERROR_NO_DATA)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("The connect to stderr of the elevated process failed: %s"), getLastErrorText()); return FALSE; } do { writeOut = 0; /* out */ if (!outClosed) { currentBlockAvail = 0; /* Check how much data is available for reading... */ ret = PeekNamedPipe(out, NULL, 0, NULL, ¤tBlockAvail, NULL); if ((ret == 0) && (GetLastError() == ERROR_BROKEN_PIPE)) { /* ERROR_BROKEN_PIPE - the client has closed the pipe. So most likely it just exited */ outClosed = TRUE; } /* currentBlockAvail is already in bytes! */ if (ret && (currentBlockAvail > 0)) { if (currentBlockAvail < 512 * sizeof(TCHAR)) { writeOut = 512 * sizeof(TCHAR); } else { writeOut = currentBlockAvail; } /* Clean the buffer before each read, as we don't want old stuff */ memset(outbuf,0, sizeof(outbuf)); if (ReadFile(out, outbuf, writeOut, &outRead, NULL) == TRUE) { /* if the message we just read in, doesn't have a new line, it means, that we most likely got the secondary process prompting sth. */ if (outbuf[_tcslen(outbuf) - 1] != TEXT('\n')) { /* To make sure, check if in is indeed waiting for input */ if (WaitForSingleObject(in, 1000) == WAIT_OBJECT_0) { /* Clean the input buffer before each read */ memset(inbuf, 0, sizeof(inbuf)); /* A prompt can have an "n" - normal at the end. So this means, that we prompt with echo */ if (outbuf[_tcslen(outbuf) - 1] == TEXT('n')) { /* clean the mark */ outbuf[_tcslen(outbuf) - 1] = TEXT('\0'); /* show the prompt */ _tprintf(TEXT("%s"), outbuf); /* and prompt */ _fgetts(inbuf, 1024, stdin); if (WriteFile(in, inbuf, (DWORD)(_tcslen(inbuf)) * sizeof(TCHAR), &inWritten, NULL) == FALSE) { /* something happened with the named pipe, get out */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Writing to the elevated process failed (%d): %s"), GetLastError(), getLastErrorText()); return FALSE; } } else if (outbuf[_tcslen(outbuf) - 1] == TEXT('p')) { /* A prompt can have an "p" - password at the end. So this means, that we prompt without showing the input on the screen */ outbuf[_tcslen(outbuf) - 1] = TEXT('\0'); /* show the prompt */ _tprintf(TEXT("%s"), outbuf); /* now read secret, readPassword already works with allocating a buffer (max 64(+1) character supported) */ secret = readPassword(); _tcsncpy(inbuf, secret, 1024); free(secret); /* "secret" does not have any delimiter we could use, so send the whole inbuf buffer */ /* this is the downside of using MESSAGE pipes */ if (WriteFile(in, inbuf, (DWORD)sizeof(inbuf), &inWritten, NULL) == FALSE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Writing to the elevated process failed (%d): %s"), GetLastError(), getLastErrorText()); return FALSE; } } else { /* no additional for the prompt was provided, but WaitForSingleObject indicates, that stdin is expecting input. Handle this as if "n" - normal was specified (without clearing the mark) /* show the prompt */ _tprintf(TEXT("%s"), outbuf); /* and prompt */ _fgetts(inbuf, 1024, stdin); if (WriteFile(in, inbuf, (DWORD)(_tcslen(inbuf)) * sizeof(TCHAR), &inWritten, NULL) == FALSE) { /* something happened with the named pipe, get out */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Writing to the elevated process failed (%d): %s"), GetLastError(), getLastErrorText()); return FALSE; } } /* this is important! for transparency writing to the elevated process works as without this layer, however, not flushing the buffer will make _getts just keep blocking until the buffer over there is full (what we don't want) */ FlushFileBuffers(in); } else { /* A timeout occured! probably a print without a newline. */ _tprintf(TEXT("%s\n"), outbuf); } } else { /* This is the normal case - just output */ /* print the message on the screen */ _tprintf(TEXT("%s"), outbuf); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Reading stdout of the elevated process failed (%d): %s"), GetLastError(), getLastErrorText()); return FALSE; } } } /* err */ /* it works almost exactly as reading stdout, except no input will be checked */ if (!errClosed) { currentBlockAvail = 0; ret = PeekNamedPipe(err, NULL, 0, NULL, ¤tBlockAvail, NULL); if ((ret == 0) && (GetLastError() == ERROR_BROKEN_PIPE)) { errClosed = TRUE; } if (ret && (currentBlockAvail > 0) && (currentBlockAvail < 512 * sizeof(TCHAR))) { memset(errbuf,0, sizeof(errbuf)); if (ReadFile(err, errbuf, currentBlockAvail, &errRead, NULL) == TRUE) { _tprintf(TEXT("%s"), errbuf); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Reading stderr of the elevated process failed (%d): %s"), GetLastError(), getLastErrorText()); return FALSE; } } } } while(!errClosed || !outClosed); return TRUE; } /* This function needs to get called from the elevated/secondary process. * It will open the named pipes, the caller has establishes and redirects stdin, stdout, stderr * to this named pipes. * All this call is doing should be transparent and (except the stdin prompting) not interfere * the secondary process (i.e. log files will still work and logging to logfile actually will be done here) * * @return If successful this function will return TRUE, FALSE otherwise */ BOOL duplicateSTD() { TCHAR* strNamedPipeNameIn, *strNamedPipeNameOut, *strNamedPipeNameErr; const TCHAR *pipeBaseName; HANDLE pipeIn, pipeOut, pipeErr; int ret, fdOut, fdIn, fdErr; size_t len; /* get the base name for the named pipe, each channel will append an additional extension */ pipeBaseName = getStringProperty(properties, TEXT("wrapper.internal.namedpipe"), NULL); len = _tcslen(pipeBaseName) + 13; strNamedPipeNameIn = malloc(sizeof(TCHAR) * len); if (!strNamedPipeNameIn) { outOfMemory(TEXT("MSE"), 1); return FALSE; } _sntprintf(strNamedPipeNameIn, len, TEXT("\\\\.\\pipe\\%sINN"), pipeBaseName); strNamedPipeNameOut = malloc(sizeof(TCHAR) * len); if (!strNamedPipeNameOut) { free(strNamedPipeNameIn); outOfMemory(TEXT("MSE"), 2); return FALSE; } _sntprintf(strNamedPipeNameOut, len, TEXT("\\\\.\\pipe\\%sOUT"), pipeBaseName); strNamedPipeNameErr = malloc(sizeof(TCHAR) * len); if (!strNamedPipeNameErr) { free(strNamedPipeNameIn); free(strNamedPipeNameOut); outOfMemory(TEXT("MSE"), 3); return FALSE; } _sntprintf(strNamedPipeNameErr, len, TEXT("\\\\.\\pipe\\%sERR"), pipeBaseName); #ifdef _DEBUG _tprintf(TEXT("going to open %s, %s and %s\n"), strNamedPipeNameIn, strNamedPipeNameOut, strNamedPipeNameErr); #endif /* Use CreateFile to connect to the Named Pipes. */ if ((pipeIn = CreateFile(strNamedPipeNameIn, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Connect to stdin pipe failed (%d): %s"), GetLastError(), getLastErrorText()); ret = FALSE; } else { if ((pipeOut = CreateFile(strNamedPipeNameOut, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Connect to stdout pipe failed (%d): %s"), GetLastError(), getLastErrorText()); ret = FALSE; } else { if ((pipeErr = CreateFile(strNamedPipeNameErr, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Connect to stderr pipe failed (%d): %s"), GetLastError(), getLastErrorText()); ret = FALSE; } else { /* This is magic */ if (((fdIn = _open_osfhandle((long)pipeIn, 0)) != -1) && ((fdErr = _open_osfhandle((long)pipeErr, 0)) != -1) && ((fdOut = _open_osfhandle((long)pipeOut, 0)) != -1)) { if ((_dup2(fdIn, 0) == 0) && (_dup2(fdOut, 1) == 0) && (_dup2(fdErr, 2) == 0)) { ret = TRUE; #ifdef _DEBUG _ftprintf(stderr, TEXT("12345\n"));fflush(NULL); _ftprintf(stderr, TEXT("1234567890\n"));fflush(NULL); _ftprintf(stdout, TEXT("12345\n"));fflush(NULL); _ftprintf(stdout, TEXT("1234567890\n"));fflush(NULL); #endif } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not redirect the file descriptors to the client sided named pipes.")); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("ERROR: Could not acquire the file descriptors for the client sided named pipes.")); } } } } free(strNamedPipeNameErr); free(strNamedPipeNameOut); free(strNamedPipeNameIn); return ret; } /* This function first creates 3 named pipes (2 inbound & 1 outbound) for establishing the connection. * Then it will ask the user to allow elevation for a secondary process. * And finally (if elevation granted) wait and call readAndWriteNamedPipes until the elevated process finishes. * * @param hwnd - The current window handle. * @param pszVerb - the verb defining the action ShellExecuteEx will perform * @param pszPath - the path to the executable going to be called * @param pszParameters - the parameters for the executable * @param pszDirectory - the working directory the process will have (if NULL the working direcory context will be inherited) * @param namedPipeName - the base name for the named pipes for the IPC between us and the new process. * @return the exit code of the elevated process */ BOOL myShellExec(HWND hwnd, LPCTSTR pszVerb, LPCTSTR pszPath, LPCTSTR pszParameters, LPCTSTR pszDirectory, TCHAR* namedPipeName) { DWORD returnValue; SHELLEXECUTEINFO shex; HANDLE hNamedPipeIn, hNamedPipeOut, hNamedPipeErr; TCHAR* strNamedPipeNameIn, *strNamedPipeNameOut, *strNamedPipeNameErr; int ret = TRUE; size_t len; /* first we generate the filenames for the named pipes based on namedPipeName */ len = _tcslen(namedPipeName) + 4 + 9; strNamedPipeNameIn = malloc(sizeof(TCHAR) * len); if (!strNamedPipeNameIn) { outOfMemory(TEXT("MSE"), 1); return TRUE; } _sntprintf(strNamedPipeNameIn, len, TEXT("\\\\.\\pipe\\%sINN"), namedPipeName); strNamedPipeNameOut = malloc(sizeof(TCHAR) * len); if (!strNamedPipeNameOut) { free(strNamedPipeNameIn); outOfMemory(TEXT("MSE"), 2); return TRUE; } _sntprintf(strNamedPipeNameOut, len, TEXT("\\\\.\\pipe\\%sOUT"), namedPipeName); strNamedPipeNameErr = malloc(sizeof(TCHAR) * len); if (!strNamedPipeNameErr) { free(strNamedPipeNameIn); free(strNamedPipeNameOut); outOfMemory(TEXT("MSE"), 3); return TRUE; } _sntprintf(strNamedPipeNameErr, len, TEXT("\\\\.\\pipe\\%sERR"), namedPipeName); /* create the process information */ memset(&shex, 0, sizeof(shex)); shex.cbSize = sizeof(SHELLEXECUTEINFO); shex.fMask = SEE_MASK_NO_CONSOLE | SEE_MASK_NOCLOSEPROCESS; shex.hwnd = hwnd; shex.lpVerb = pszVerb; shex.lpFile = pszPath; shex.lpParameters = pszParameters; shex.lpDirectory = pszDirectory; #ifdef _DEBUG shex.nShow = SW_SHOWNORMAL; #else shex.nShow = SW_HIDE; #endif hNamedPipeIn = CreateNamedPipe(strNamedPipeNameIn, PIPE_ACCESS_OUTBOUND , PIPE_TYPE_BYTE | // message type pipe PIPE_READMODE_BYTE | // message-read mode PIPE_WAIT, // blocking mode 1, // max. instances 1024 * sizeof(TCHAR), // output buffer size 1024*sizeof(TCHAR), // input buffer size 0, // client time-out NULL); // default security attribute if (hNamedPipeIn == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Stdin CreateNamedPipe failed (%d): %s"), GetLastError(), getLastErrorText()); ret = TRUE; } else { hNamedPipeOut = CreateNamedPipe(strNamedPipeNameOut, PIPE_ACCESS_INBOUND , PIPE_TYPE_MESSAGE | // message type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_NOWAIT, // nonblocking mode 1, // max. instances 512 * sizeof(TCHAR), // output buffer size 512 * sizeof(TCHAR), // input buffer size 0, // client time-out NULL); // default security attribute if (hNamedPipeOut == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Stdout CreateNamedPipe failed (%d): %s"), GetLastError(), getLastErrorText()); ret = TRUE; } else { hNamedPipeErr = CreateNamedPipe(strNamedPipeNameErr, PIPE_ACCESS_INBOUND , PIPE_TYPE_MESSAGE | // message type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_NOWAIT, // nonblocking mode 1, // max. instances 512 * sizeof(TCHAR), // output buffer size 512 * sizeof(TCHAR), // input buffer size 0, // client time-out NULL); // default security attribute if (hNamedPipeErr == INVALID_HANDLE_VALUE) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Stderr CreateNamedPipe failed (%d): %s"), GetLastError(), getLastErrorText()); ret = TRUE; } else { /* Now launch the process */ if (ShellExecuteEx(&shex) == TRUE) { if (shex.hProcess != NULL) { /* now read and write the pipes */ if (readAndWriteNamedPipes(hNamedPipeIn, hNamedPipeOut, hNamedPipeErr) != TRUE) { // the error should have already been reported. } /* Wait up to 1 sec to check if the elevated process really exited */ returnValue = WaitForSingleObject(shex.hProcess, 1000); if (returnValue == WAIT_OBJECT_0) { if (!GetExitCodeProcess(shex.hProcess, &ret)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("WaitThread for Backend-Process: %s failed! (%d): %s"), TEXT("GetExitCodeProcess"), GetLastError(), getLastErrorText()); ret = TRUE; } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("The elevated Wrapper process is still alive. Trying to kill it. (%d): %s"), GetLastError(), getLastErrorText()); if (TerminateProcess(shex.hProcess, 1) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Failed to kill the elevated Wrapper process. (%d): %s"), GetLastError(), getLastErrorText()); } ret = TRUE; } } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Failed to obtain elevated status. (%d): %s"), GetLastError(), getLastErrorText()); ret = TRUE; } CloseHandle(hNamedPipeErr); } CloseHandle(hNamedPipeOut); } CloseHandle(hNamedPipeIn); } free(strNamedPipeNameIn); free(strNamedPipeNameOut); free(strNamedPipeNameErr); return ret; } /* * This is just a wrapper function between elevateThis and myShellExec filling in the verb * For more information please refer to myShellExec */ BOOL runElevated(__in LPCTSTR pszPath, __in_opt LPCTSTR pszParameters, __in_opt LPCTSTR pszDirectory, TCHAR* namedPipeName) { return myShellExec(NULL, TEXT("runas"), pszPath, pszParameters, pszDirectory, namedPipeName); } /* * This is the entry point on the user side for creating an elevated process. * UAC does not allow to give a running process elevated privileges, so the * wrapper has to create a copy of the current process, arm it with elevated * privileges and take care of IPC. * * @return exit code of backend process */ BOOL elevateThis(int argc, TCHAR **argv) { int i, namedPipeInserted = 0, ret = FALSE; size_t len = 0; TCHAR szPath[_MAX_PATH]; TCHAR *parameter; TCHAR* strNamedPipeName; /* get the file name of the binary, we can't trust argv[0] as the working * directory might have been changed. */ if (GetModuleFileName(NULL, szPath, _MAX_PATH)) { /* seed the pseudo-random generator */ srand((unsigned)time(NULL)); strNamedPipeName = malloc(sizeof(TCHAR) * 11); if (!strNamedPipeName) { outOfMemory(TEXT("MSE"), 1); return TRUE; } /* create a pseudo-random 10 digit string */ _sntprintf(strNamedPipeName, 11, TEXT("%05d%05d"), rand() % 100000, rand() % 100000); /* ShellExecuteEx is expecting the parameter in a single string */ for (i = 1; i < argc; i++) { /* if '--' was specified, wrapperParseArguments has replaced this parameter with NULL */ if (argv[i] == NULL) { len += 3; } else { /* insert a space and qoutes */ len += _tcslen(argv[i]) + 3; } } /* add space for the namedpipe and console flush property */ len += _tcslen(strNamedPipeName) + 28 + 27; parameter = calloc(len, sizeof(TCHAR)); if (!parameter) { outOfMemory(TEXT("ET"), 1); return TRUE; } /* now fill the parameter */ for (i = 1; i < argc; i++) { if (i != 1) { _tcsncat(parameter, TEXT(" "), len); } if (argv[i] == NULL) { /* the additional parameters have to be inserted before the '--'. */ _tcsncat(parameter, TEXT("wrapper.console.flush=true wrapper.internal.namedpipe="), len); _tcsncat(parameter, strNamedPipeName, len); namedPipeInserted = 1; _tcsncat(parameter, TEXT(" --"), len); } else { _tcsncat(parameter, TEXT("\""), len); _tcsncat(parameter, argv[i], len); _tcsncat(parameter, TEXT("\""), len); } } if (!namedPipeInserted) { _tcsncat(parameter, TEXT(" wrapper.console.flush=true wrapper.internal.namedpipe="), len); _tcsncat(parameter, strNamedPipeName, len); } ret = runElevated(szPath, parameter, NULL, strNamedPipeName); free(strNamedPipeName); free(parameter); return ret; } return TRUE; } #endif /* ifdef WIN32 */ wrapper_3.5.26_src/src/c/wrappereventloop.c100644 0 0 331707 12440202301 16177 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * This file contains the main event loop and state engine for * the Java Service Wrapper. * * Author: * Leif Mortenson * Ryan Shaw */ #include #include #include #include #ifdef WIN32 #include /* MS Visual Studio 8 went and deprecated the POXIX names for functions. * Fixing them all would be a big headache for UNIX versions. */ #pragma warning(disable : 4996) #else /* UNIX */ #include #include #endif #include "wrapper.h" #include "logger.h" #include "wrapper_i18n.h" #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif /** * Returns a constant text representation of the specified Wrapper State. * * @param wState The Wrapper State whose name is being requested. * * @return Thre requested Wrapper State. */ const TCHAR *wrapperGetWState(int wState) { const TCHAR *name; switch(wState) { case WRAPPER_WSTATE_STARTING: name = TEXT("STARTING"); break; case WRAPPER_WSTATE_STARTED: name = TEXT("STARTED"); break; case WRAPPER_WSTATE_PAUSING: name = TEXT("PAUSING"); break; case WRAPPER_WSTATE_PAUSED: name = TEXT("PAUSED"); break; case WRAPPER_WSTATE_RESUMING: name = TEXT("RESUMING"); break; case WRAPPER_WSTATE_STOPPING: name = TEXT("STOPPING"); break; case WRAPPER_WSTATE_STOPPED: name = TEXT("STOPPED"); break; default: name = TEXT("UNKNOWN"); break; } return name; } /** * Returns a constant text representation of the specified Java State. * * @param jState The Java State whose name is being requested. * * @return Thre requested Java State. */ const TCHAR *wrapperGetJState(int jState) { const TCHAR *name; switch(jState) { case WRAPPER_JSTATE_DOWN_CLEAN: name = TEXT("DOWN_CLEAN"); break; case WRAPPER_JSTATE_LAUNCH_DELAY: name = TEXT("LAUNCH(DELAY)"); break; case WRAPPER_JSTATE_RESTART: name = TEXT("RESTART"); break; case WRAPPER_JSTATE_LAUNCH: name = TEXT("LAUNCH"); break; case WRAPPER_JSTATE_LAUNCHING: name = TEXT("LAUNCHING"); break; case WRAPPER_JSTATE_LAUNCHED: name = TEXT("LAUNCHED"); break; case WRAPPER_JSTATE_STARTING: name = TEXT("STARTING"); break; case WRAPPER_JSTATE_STARTED: name = TEXT("STARTED"); break; case WRAPPER_JSTATE_STOP: name = TEXT("STOP"); break; case WRAPPER_JSTATE_STOPPING: name = TEXT("STOPPING"); break; case WRAPPER_JSTATE_STOPPED: name = TEXT("STOPPED"); break; case WRAPPER_JSTATE_KILLING: name = TEXT("KILLING"); break; case WRAPPER_JSTATE_KILL: name = TEXT("KILL"); break; case WRAPPER_JSTATE_DOWN_CHECK: name = TEXT("DOWN_CHECK"); break; case WRAPPER_JSTATE_DOWN_FLUSH: name = TEXT("DOWN_FLUSH"); break; case WRAPPER_JSTATE_KILLED: name = TEXT("KILLED"); break; default: name = TEXT("UNKNOWN"); break; } return name; } void writeStateFile(const TCHAR *filename, const TCHAR *state, int newUmask) { FILE *fp = NULL; int old_umask; int cnt = 0; /* If other processes are reading the state file it may be locked for a moment. * Avoid problems by trying a few times before giving up. */ while (cnt < 10) { #ifdef WIN32 old_umask = umask(newUmask); fp = _tfopen(filename, TEXT("w")); umask(old_umask); #else old_umask = umask(newUmask); fp = _tfopen(filename, TEXT("w")); umask(old_umask); #endif if (fp != NULL) { _ftprintf(fp, TEXT("%s\n"), state); fclose(fp); return; } /* Sleep for a tenth of a second. */ wrapperSleep(100); cnt++; } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to write to the status file: %s"), filename); } /** * Changes the current Wrapper state. * * wState - The new Wrapper state. */ void wrapperSetWrapperState(int wState) { if (wrapperData->isStateOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Set Wrapper State %s -> %s"), wrapperGetWState(wrapperData->wState), wrapperGetWState(wState)); } wrapperData->wState = wState; if (wrapperData->statusFilename != NULL) { writeStateFile(wrapperData->statusFilename, wrapperGetWState(wrapperData->wState), wrapperData->statusFileUmask); } } /** * Updates the current state time out. * * nowTicks - The current tick count at the time of the call, ignored if * delay is negative. * delay - The delay in seconds, added to the nowTicks after which the state * will time out, if negative will never time out. */ void wrapperUpdateJavaStateTimeout(TICKS nowTicks, int delay) { TICKS newTicks; int ignore; int tickAge; if (delay >= 0) { newTicks = wrapperAddToTicks(nowTicks, delay); ignore = FALSE; if (wrapperData->jStateTimeoutTicksSet) { /* We need to make sure that the new delay is longer than the existing one. * This is complicated slightly because the tick counter can be wrapped. */ tickAge = wrapperGetTickAgeTicks(wrapperData->jStateTimeoutTicks, newTicks); if (tickAge <= 0) { ignore = TRUE; } } if (ignore) { /* The new value is meaningless. */ if (wrapperData->isStateOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Set Java State %s (%d) Ignored Timeout %08x"), wrapperGetJState(wrapperData->jState), delay, wrapperData->jStateTimeoutTicks); } } else { if (wrapperData->isStateOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Set Java State %s (%d) Timeout %08x -> %08x"), wrapperGetJState(wrapperData->jState), delay, nowTicks, delay, newTicks); } wrapperData->jStateTimeoutTicks = newTicks; wrapperData->jStateTimeoutTicksSet = 1; } } else { wrapperData->jStateTimeoutTicks = 0; wrapperData->jStateTimeoutTicksSet = 0; } } /** * Changes the current Java state. * * jState - The new Java state. * nowTicks - The current tick count at the time of the call, ignored if * delay is negative. * delay - The delay in seconds, added to the nowTicks after which the state * will time out, if negative will never time out. */ void wrapperSetJavaState(int jState, TICKS nowTicks, int delay) { if (wrapperData->isStateOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Set Java State %s -> %s"), wrapperGetJState(wrapperData->jState), wrapperGetJState(jState)); } if (wrapperData->jState != jState) { /* If the state has changed, then the old timeout will never be used. * Clear it here so any new timeout will be used. */ wrapperData->jStateTimeoutTicks = 0; wrapperData->jStateTimeoutTicksSet = 0; } wrapperData->jState = jState; wrapperUpdateJavaStateTimeout(nowTicks, delay); if (wrapperData->javaStatusFilename != NULL) { writeStateFile(wrapperData->javaStatusFilename, wrapperGetJState(wrapperData->jState), wrapperData->javaStatusFileUmask); } } void displayLaunchingTimeoutMessage() { const TCHAR *mainClass; log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Startup failed: Timed out waiting for a signal from the JVM.")); mainClass = getStringProperty(properties, TEXT("wrapper.java.mainclass"), TEXT("Main")); if ((_tcsstr(mainClass, TEXT("org.tanukisoftware.wrapper.WrapperSimpleApp")) != NULL) || (_tcsstr(mainClass, TEXT("org.tanukisoftware.wrapper.WrapperStartStopApp")) != NULL)) { /* The user appears to be using a valid main class, so no advice available. */ } else { if (wrapperData->isAdviserEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("------------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("Advice:") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("The Wrapper consists of a native component as well as a set of classes\nwhich run within the JVM that it launches. The Java component of the\nWrapper must be initialized promptly after the JVM is launched or the\nWrapper will timeout, as just happened. Most likely the main class\nspecified in the Wrapper configuration file is not correctly initializing\nthe Wrapper classes:")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT(" %s"), mainClass); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("While it is possible to do so manually, the Wrapper ships with helper\nclasses to make this initialization processes automatic.\nPlease review the integration section of the Wrapper's documentation\nfor the various methods which can be employed to launch an application\nwithin the Wrapper:")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT(" http://wrapper.tanukisoftware.com/doc/english/integrate.html")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("------------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ADVICE, TEXT("") ); } } } /** * Handles a timeout for a DebugJVM by showing an appropriate message and * resetting internal timeouts. */ void handleDebugJVMTimeout(TICKS nowTicks, const TCHAR *message, const TCHAR *timer) { if (!wrapperData->debugJVMTimeoutNotified) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("------------------------------------------------------------------------") ); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("%s"), message); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("The JVM was launched with debug options so this may be because the JVM\nis currently suspended by a debugger. Any future timeouts during this\nJVM invocation will be silently ignored.")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("------------------------------------------------------------------------") ); } wrapperData->debugJVMTimeoutNotified = TRUE; /* Make this individual state never timeout then continue. */ if (wrapperData->isStateOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" DebugJVM timeout. Disable current %s timeout."), timer); } wrapperUpdateJavaStateTimeout(nowTicks, -1); } /** * Tests for the existence of the anchor file. If it does not exist then * the Wrapper will begin its shutdown process. * * nowTicks: The tick counter value this time through the event loop. */ void anchorPoll(TICKS nowTicks) { #if defined(WIN32) && !defined(WIN64) struct _stat64i32 fileStat; #else struct stat fileStat; #endif int result; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Anchor timeout=%d, now=%d"), wrapperData->anchorTimeoutTicks, nowTicks); #endif if (wrapperData->anchorFilename) { if (wrapperTickExpired(nowTicks, wrapperData->anchorTimeoutTicks)) { if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: check anchor file")); } result = _tstat(wrapperData->anchorFilename, &fileStat); if (result == 0) { /* Anchor file exists. Do nothing. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("The anchor file %s exists."), wrapperData->anchorFilename); #endif } else { /* Anchor file is gone. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("The anchor file %s was deleted."), wrapperData->anchorFilename); #endif /* Unless we are already doing so, start the shudown process. */ if (wrapperData->exitRequested || wrapperData->restartRequested || (wrapperData->jState == WRAPPER_JSTATE_STOP) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED) || (wrapperData->jState == WRAPPER_JSTATE_KILLING) || (wrapperData->jState == WRAPPER_JSTATE_KILL) || (wrapperData->jState == WRAPPER_JSTATE_KILLED) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN)) { /* Already shutting down, so nothing more to do. */ } else { /* Always force the shutdown as this was an external event. */ wrapperStopProcess(0, TRUE); } /* To make sure that the JVM will not be restarted for any reason, * start the Wrapper shutdown process as well. */ if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { /* Already stopping. */ } else { /* Start the shutdown process. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Anchor file deleted. Shutting down.")); wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } } wrapperData->anchorTimeoutTicks = wrapperAddToTicks(nowTicks, wrapperData->anchorPollInterval); } } } /** * Tests for the existence of the command file. If it exists then it will be * opened and any included commands will be processed. On completion, the * file will be deleted. * * nowTicks: The tick counter value this time through the event loop. */ #define MAX_COMMAND_LENGTH 80 void commandPoll(TICKS nowTicks) { #if defined(WIN32) && !defined(WIN64) struct _stat64i32 fileStat; #else struct stat fileStat; #endif int result; FILE *stream; int cnt; TCHAR buffer[MAX_COMMAND_LENGTH]; TCHAR *c; TCHAR *d; TCHAR *command; TCHAR *param1; TCHAR *param2; int exitCode; int pauseTime; int logLevel; int oldLowLogLevel; int newLowLogLevel; int flag; int accessViolation = FALSE; #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Command timeout=%08x, now=%08x"), wrapperData->commandTimeoutTicks, nowTicks); #endif if (wrapperData->commandFilename) { if (wrapperTickExpired(nowTicks, wrapperData->commandTimeoutTicks)) { if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: check command file")); } result = _tstat(wrapperData->commandFilename, &fileStat); if (result == 0) { /* Command file exists. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("The command file %s exists."), wrapperData->commandFilename); #endif /* We need to be able to lock and then read the command file. Other * applications will be creating this file so we need to handle the * case where it is locked for a few moments. */ cnt = 0; do { stream = _tfopen(wrapperData->commandFilename, TEXT("r+t")); if (stream == NULL) { /* Sleep for a tenth of a second. */ wrapperSleep(100); } cnt++; } while ((cnt < 10) && (stream == NULL)); if (stream == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Unable to read the command file: %s"), wrapperData->commandFilename); } else { /* Read in each of the commands line by line. */ do { c = _fgetts(buffer, MAX_COMMAND_LENGTH, stream); if (c != NULL) { /* Always strip both ^M and ^J off the end of the line, this is done rather * than simply checking for \n so that files will work on all platforms * even if their line feeds are incorrect. */ if ((d = _tcschr(buffer, 13 /* ^M */)) != NULL) { d[0] = TEXT('\0'); } if ((d = _tcschr(buffer, 10 /* ^J */)) != NULL) { d[0] = TEXT('\0'); } command = buffer; /** Look for the first space, everything after it will be the parameter(s). */ /* Look for parameter 1. */ if ((param1 = _tcschr(buffer, ' ')) != NULL ) { param1[0] = TEXT('\0'); /* Terminate the command. */ /* Find the first non-space character. */ do { param1++; } while (param1[0] == TEXT(' ')); } if (param1 != NULL) { /* Look for parameter 2. */ if ((param2 = _tcschr(param1, ' ')) != NULL ) { param2[0] = TEXT('\0'); /* Terminate param1. */ /* Find the first non-space character. */ do { param2++; } while (param2[0] == TEXT(' ')); } if (param2 != NULL) { /* Make sure parameter 2 is terminated. */ if ((d = _tcschr(param2, ' ')) != NULL ) { d[0] = TEXT('\0'); /* Terminate param2. */ } } } else { param2 = NULL; } /* Process the command. */ if (strcmpIgnoreCase(command, TEXT("RESTART")) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. %s"), command, wrapperGetRestartProcessMessage()); wrapperRestartProcess(); } else if (strcmpIgnoreCase(command, TEXT("STOP")) == 0) { if (param1 == NULL) { exitCode = 0; } else { exitCode = _ttoi(param1); } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Shutting down with exit code %d."), command, exitCode); /* Always force the shutdown as this is an external event. */ wrapperStopProcess(exitCode, TRUE); /* To make sure that the JVM will not be restarted for any reason, * start the Wrapper shutdown process as well. */ if ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED)) { /* Already stopping. */ } else { wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } } else if (strcmpIgnoreCase(command, TEXT("PAUSE")) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Pausing JVM."), command); wrapperPauseProcess(WRAPPER_ACTION_SOURCE_CODE_COMMANDFILE); } else if (strcmpIgnoreCase(command, TEXT("RESUME")) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Resuming JVM."), command); wrapperResumeProcess(WRAPPER_ACTION_SOURCE_CODE_COMMANDFILE); } else if (strcmpIgnoreCase(command, TEXT("DUMP")) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Requesting a Thread Dump."), command); wrapperRequestDumpJVMState(); } else if (strcmpIgnoreCase(command, TEXT("GC")) == 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Requesting a GC."), command); wrapperRequestJVMGC(WRAPPER_ACTION_SOURCE_CODE_COMMANDFILE); } else if ((strcmpIgnoreCase(command, TEXT("CONSOLE_LOGLEVEL")) == 0) || (strcmpIgnoreCase(command, TEXT("LOGFILE_LOGLEVEL")) == 0) || (strcmpIgnoreCase(command, TEXT("SYSLOG_LOGLEVEL")) == 0)) { if (param1 == NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s' is missing its log level."), command); } else { logLevel = getLogLevelForName(param1); if (logLevel == LEVEL_UNKNOWN) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s' specified an unknown log level: '%'"), command, param1); } else { oldLowLogLevel = getLowLogLevel(); if (strcmpIgnoreCase(command, TEXT("CONSOLE_LOGLEVEL")) == 0) { setConsoleLogLevelInt(logLevel); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Set console log level to '%s'."), command, param1); } else if (strcmpIgnoreCase(command, TEXT("LOGFILE_LOGLEVEL")) == 0) { setLogfileLevelInt(logLevel); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Set log file log level to '%s'."), command, param1); } else if (strcmpIgnoreCase(command, TEXT("SYSLOG_LOGLEVEL")) == 0) { setSyslogLevelInt(logLevel); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Set syslog log level to '%s'."), command, param1); } else { /* Shouldn't get here. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s' lead to an unexpected state."), command); } newLowLogLevel = getLowLogLevel(); if (oldLowLogLevel != newLowLogLevel) { wrapperData->isDebugging = (newLowLogLevel <= LEVEL_DEBUG); _sntprintf(buffer, MAX_COMMAND_LENGTH, TEXT("%d"), getLowLogLevel()); wrapperProtocolFunction(WRAPPER_MSG_LOW_LOG_LEVEL, buffer); } } } } else if ((strcmpIgnoreCase(command, TEXT("LOOP_OUTPUT")) == 0) || (strcmpIgnoreCase(command, TEXT("STATE_OUTPUT")) == 0) || (strcmpIgnoreCase(command, TEXT("MEMORY_OUTPUT")) == 0) || (strcmpIgnoreCase(command, TEXT("CPU_OUTPUT")) == 0) || (strcmpIgnoreCase(command, TEXT("TIMER_OUTPUT")) == 0) || (strcmpIgnoreCase(command, TEXT("SLEEP_OUTPUT")) == 0)) { flag = ((param1 != NULL) && (strcmpIgnoreCase(param1, TEXT("TRUE")) == 0)); if (strcmpIgnoreCase(command, TEXT("LOOP_OUTPUT")) == 0) { wrapperData->isLoopOutputEnabled = flag; } else if (strcmpIgnoreCase(command, TEXT("STATE_OUTPUT")) == 0) { wrapperData->isStateOutputEnabled = flag; } else if (strcmpIgnoreCase(command, TEXT("MEMORY_OUTPUT")) == 0) { wrapperData->isMemoryOutputEnabled = flag; } else if (strcmpIgnoreCase(command, TEXT("CPU_OUTPUT")) == 0) { wrapperData->isCPUOutputEnabled = flag; } else if (strcmpIgnoreCase(command, TEXT("TIMER_OUTPUT")) == 0) { wrapperData->isTickOutputEnabled = flag; } else if (strcmpIgnoreCase(command, TEXT("SLEEP_OUTPUT")) == 0) { wrapperData->isSleepOutputEnabled = flag; } if (flag) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Enable %s."), command, command); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Command '%s'. Disable %s."), command, command); } } else if ((strcmpIgnoreCase(command, TEXT("CLOSE_SOCKET")) == 0) || (strcmpIgnoreCase(command, TEXT("CLOSE_BACKEND")) == 0)) { if (wrapperData->commandFileTests) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Closing backend socket to JVM..."), command); wrapperProtocolClose(); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Tests disabled."), command); } } else if (strcmpIgnoreCase(command, TEXT("PAUSE_THREAD")) == 0) { if (wrapperData->commandFileTests) { if (param2 == NULL) { pauseTime = -1; } else { pauseTime = __max(0, __min(3600, _ttoi(param2))); } if (strcmpIgnoreCase(param1, TEXT("MAIN")) == 0) { wrapperData->pauseThreadMain = pauseTime; } else if (strcmpIgnoreCase(param1, TEXT("TIMER")) == 0) { wrapperData->pauseThreadTimer = pauseTime; } else if (strcmpIgnoreCase(param1, TEXT("JAVAIO")) == 0) { wrapperData->pauseThreadJavaIO = pauseTime; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Enqueue request to pause unknown thread."), command); pauseTime = 0; } if (pauseTime > 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Enqueue request to pause %s thread for %d seconds..."), command, param1, pauseTime); } else if (pauseTime < 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Enqueue request to pause %s thread indefinitely..."), command, param1); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Tests disabled."), command); } } else if (strcmpIgnoreCase(command, TEXT("PAUSE_LOGGER")) == 0) { if (wrapperData->commandFileTests) { if (param1 == NULL) { pauseTime = -1; } else { pauseTime = __max(0, __min(3600, _ttoi(param1))); } if (pauseTime > 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Enqueue request to pause logger for %d seconds..."), command, pauseTime); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Enqueue request to pause logger indefinitely..."), command); } setPauseTime(pauseTime); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Tests disabled."), command); } } else if (strcmpIgnoreCase(command, TEXT("ACCESS_VIOLATION")) == 0) { if (wrapperData->commandFileTests) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Command '%s'. Intentionally causing an Access Violation in Wrapper..."), command); /* We can't do the access violation here because we want to make sure the * file is deleted first, otherwise it be executed again when the Wrapper is restarted. */ accessViolation = TRUE; } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s'. Tests disabled."), command); } } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Command '%s' is unknown, ignoring."), command); } } } while (c != NULL); /* Close the file. */ fclose(stream); /* Delete the file. */ if (_tremove(wrapperData->commandFilename) == -1) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Unable to delete the command file, %s: %s"), wrapperData->commandFilename, getLastErrorText()); } if (accessViolation) { /* Make sure that everything is logged before the crash. */ flushLogfile(); /* Actually cause the access violation. */ c = NULL; c[0] = TEXT('\0'); /* Should never get here. */ } } } else { /* Command file does not exist. */ #ifdef _DEBUG log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("The command file %s does not exist."), wrapperData->commandFilename); #endif } wrapperData->commandTimeoutTicks = wrapperAddToTicks(nowTicks, wrapperData->commandPollInterval); } } } /******************************************************************** * Wrapper States *******************************************************************/ /** * WRAPPER_WSTATE_STARTING * The Wrapper process is being started. It will remain in this state * until a JVM and its application has been successfully started. * * nowTicks: The tick counter value this time through the event loop. */ void wStateStarting(TICKS nowTicks) { int timeout; /* While the wrapper is starting up, we need to ping the service */ /* manager to reasure it that we are still alive. */ /* Tell the service manager that we are starting */ if (wrapperData->startupTimeout > 0) { timeout = (wrapperData->startupTimeout) * 1000; } else { timeout = 86400000; /* Set infinity at 1 day. */ } wrapperReportStatus(FALSE, WRAPPER_WSTATE_STARTING, 0, timeout); /* If we are supposed to pause on startup, we need to jump to that state now, and report that we are started. */ if (wrapperData->initiallyPaused && wrapperData->pausable) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Initially Paused.")); wrapperSetWrapperState(WRAPPER_WSTATE_PAUSED); /* Tell the service manager that we started */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_PAUSED, 0, 0); } else { /* If the JVM state is now STARTED, then change the wrapper state */ /* to be STARTED as well. */ if (wrapperData->jState == WRAPPER_JSTATE_STARTED) { wrapperSetWrapperState(WRAPPER_WSTATE_STARTED); /* Tell the service manager that we started */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_STARTED, 0, 0); } } } /** * WRAPPER_WSTATE_STARTED * The Wrapper process is started. It will remain in this state until * the Wrapper is ready to start shutting down. The JVM process may * be restarted one or more times while the Wrapper is in this state. * * nowTicks: The tick counter value this time through the event loop. */ void wStateStarted(TICKS nowTicks) { /* Just keep running. Nothing to do here. */ } /** * WRAPPER_WSTATE_PAUSING * The Wrapper process is being paused. If stopping the JVM is enabled * then it will remain in this state until the JVM has been stopped. * Otherwise it will immediately go to the WRAPPER_WSTATE_PAUSED state. * * nowTicks: The tick counter value this time through the event loop. */ void wStatePausing(TICKS nowTicks) { int timeout; /* While the wrapper is pausing, we need to ping the service */ /* manager to reasure it that we are still alive. */ /* If we are configured to do so, stop the JVM */ if (wrapperData->pausableStopJVM) { /* If it has not already been set, set the exit request flag. */ if (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) { /* JVM is now down. We are now paused. */ wrapperSetWrapperState(WRAPPER_WSTATE_PAUSED); /* Tell the service manager that we are paused */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_PAUSED, 0, 0); } else { /* Tell the service manager that we are pausing */ if ((wrapperData->shutdownTimeout <= 0) || (wrapperData->jvmExitTimeout <= 0)) { timeout = 86400000; /* Set infinity at 1 day. */ } else { timeout = MAX(wrapperData->shutdownTimeout, wrapperData->jvmExitTimeout) * 1000; } wrapperReportStatus(FALSE, WRAPPER_WSTATE_PAUSING, 0, timeout); if (wrapperData->exitRequested || (wrapperData->jState == WRAPPER_JSTATE_STOP) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED) || (wrapperData->jState == WRAPPER_JSTATE_KILLING) || (wrapperData->jState == WRAPPER_JSTATE_KILL) || (wrapperData->jState == WRAPPER_JSTATE_KILLED) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH)) { /* In the process of stopping the JVM. */ } else { /* The JVM needs to be stopped, start that process. */ wrapperData->exitRequested = TRUE; /* Make sure the JVM will be restarted. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_CONFIGURED; } } } else { /* We want to leave the JVM process as is. We are now paused. */ wrapperSetWrapperState(WRAPPER_WSTATE_PAUSED); /* Tell the service manager that we are paused */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_PAUSED, 0, 0); } } /** * WRAPPER_WSTATE_PAUSED * The Wrapper process is paused. It will remain in this state until * the Wrapper is resumed or is ready to start shutting down. The * JVM may be stopped or will remain stopped while the Wrapper is in * this state. * * nowTicks: The tick counter value this time through the event loop. */ void wStatePaused(TICKS nowTicks) { /* Just keep running. Nothing to do here. */ } /** * WRAPPER_WSTATE_RESUMING * The Wrapper process is being resumed. We will remain in this state * until the JVM enters the running state. It may or may not be initially * started. * * nowTicks: The tick counter value this time through the event loop. */ void wStateResuming(TICKS nowTicks) { int timeout; /* While the wrapper is resuming, we need to ping the service */ /* manager to reasure it that we are still alive. */ /* If the JVM state is now STARTED, then change the wrapper state */ /* to be STARTED as well. */ if (wrapperData->jState == WRAPPER_JSTATE_STARTED) { wrapperSetWrapperState(WRAPPER_WSTATE_STARTED); /* Tell the service manager that we started */ wrapperReportStatus(FALSE, WRAPPER_WSTATE_STARTED, 0, 0); } else { /* JVM is down and so it needs to be started. */ /* Tell the service manager that we are resuming */ if (wrapperData->startupTimeout > 0) { timeout = wrapperData->startupTimeout * 1000; } else { timeout = 86400000; /* Set infinity at 1 day. */ } wrapperReportStatus(FALSE, WRAPPER_WSTATE_RESUMING, 0, timeout); } } /** * WRAPPER_WSTATE_STOPPING * The Wrapper process has started its shutdown process. It will * remain in this state until it is confirmed that the JVM has been * stopped. * * nowTicks: The tick counter value this time through the event loop. */ void wStateStopping(TICKS nowTicks) { int timeout; /* The wrapper is stopping, we need to ping the service manager * to reasure it that we are still alive. */ /* Tell the service manager that we are stopping */ if ((wrapperData->shutdownTimeout <= 0) || (wrapperData->jvmExitTimeout <= 0)) { timeout = 86400000; /* Set infinity at 1 day. */ } else { timeout = MAX(wrapperData->shutdownTimeout, wrapperData->jvmExitTimeout) * 1000; } wrapperReportStatus(FALSE, WRAPPER_WSTATE_STOPPING, wrapperData->exitCode, timeout); /* If the JVM state is now DOWN_CLEAN, then change the wrapper state * to be STOPPED as well. */ if (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) { wrapperSetWrapperState(WRAPPER_WSTATE_STOPPED); /* Don't tell the service manager that we stopped here. That * will be done when the application actually quits. */ } } /** * WRAPPER_WSTATE_STOPPED * The Wrapper process is now ready to exit. The event loop will complete * and the Wrapper process will exit. * * nowTicks: The tick counter value this time through the event loop. */ void wStateStopped(TICKS nowTicks) { /* The wrapper is ready to stop. Nothing to be done here. This */ /* state will exit the event loop below. */ } /******************************************************************** * JVM States *******************************************************************/ /** * WRAPPER_JSTATE_DOWN_CLEAN * The JVM process currently does not exist and we are clean. Depending * on the Wrapper state and other factors, we will either stay in this * state or switch to the LAUNCH state causing a JVM to be launched * after a delay set in this function. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateDownClean(TICKS nowTicks, int nextSleep) { TCHAR onExitParamBuffer[16 + 10 + 1]; const TCHAR *onExitAction; int startupDelay; int restartMode; /* The JVM can be down for one of 4 reasons. The first is that the * wrapper is just starting. The second is that the JVM is being * restarted for some reason, the 3rd is that the wrapper is paused, * and the 4th is that the wrapper is trying to shut down. */ if ((wrapperData->wState == WRAPPER_WSTATE_STARTING) || (wrapperData->wState == WRAPPER_WSTATE_STARTED) || (wrapperData->wState == WRAPPER_WSTATE_RESUMING)) { if (wrapperData->restartRequested) { /* A JVM needs to be launched. */ restartMode = wrapperData->restartRequested; wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_NO; wrapperData->stoppedPacketReceived = FALSE; wrapperData->restartPacketReceived = FALSE; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Preparing to restart with mode %d."), restartMode); } /* Depending on the number of restarts to date, decide how to handle the (re)start. */ if (wrapperData->jvmRestarts > 0) { /* This is not the first JVM, so make sure that we still want to launch. */ if ((wrapperData->wState == WRAPPER_WSTATE_RESUMING) && wrapperData->pausableStopJVM) { /* We are resuming and the JVM was expected to be stopped. Always launch * immediately and reset the failed invocation count. * This mode of restarts works even if restarts have been disabled. */ wrapperData->failedInvocationCount = 0; wrapperSetJavaState(WRAPPER_JSTATE_LAUNCH_DELAY, nowTicks, 0); } else if ((restartMode == WRAPPER_RESTART_REQUESTED_AUTOMATIC) && wrapperData->isAutoRestartDisabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Automatic JVM Restarts disabled. Shutting down.")); wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } else if (wrapperData->isRestartDisabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("JVM Restarts disabled. Shutting down.")); wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } else if (wrapperGetTickAgeSeconds(wrapperData->jvmLaunchTicks, nowTicks) >= wrapperData->successfulInvocationTime) { /* The previous JVM invocation was running long enough that its invocation */ /* should be considered a success. Reset the failedInvocationStart to */ /* start the count fresh. */ wrapperData->failedInvocationCount = 0; /* Set the state to launch after the restart delay. */ wrapperSetJavaState(WRAPPER_JSTATE_LAUNCH_DELAY, nowTicks, wrapperData->restartDelay); if (wrapperData->restartDelay > 0) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Waiting %d seconds before launching another JVM."), wrapperData->restartDelay); } } } else { /* The last JVM invocation died quickly and was considered to have */ /* been a faulty launch. Increase the failed count. */ wrapperData->failedInvocationCount++; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM was only running for %d seconds leading to a failed restart count of %d."), wrapperGetTickAgeSeconds(wrapperData->jvmLaunchTicks, nowTicks), wrapperData->failedInvocationCount); } /* See if we are allowed to try restarting the JVM again. */ if (wrapperData->failedInvocationCount < wrapperData->maxFailedInvocations) { /* Try reslaunching the JVM */ /* Set the state to launch after the restart delay. */ wrapperSetJavaState(WRAPPER_JSTATE_LAUNCH_DELAY, nowTicks, wrapperData->restartDelay); if (wrapperData->restartDelay > 0) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Waiting %d seconds before launching another JVM."), wrapperData->restartDelay); } } } else { /* Unable to launch another JVM. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("There were %d failed launches in a row, each lasting less than %d seconds. Giving up."), wrapperData->failedInvocationCount, wrapperData->successfulInvocationTime); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT(" There may be a configuration problem: please check the logs.")); wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } } } else { /* This will be the first invocation. */ wrapperData->failedInvocationCount = 0; /* Set the state to launch after the startup delay. */ if (wrapperData->isConsole) { startupDelay = wrapperData->startupDelayConsole; } else { startupDelay = wrapperData->startupDelayService; } wrapperSetJavaState(WRAPPER_JSTATE_LAUNCH_DELAY, nowTicks, startupDelay); if (startupDelay > 0) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Waiting %d seconds before launching the first JVM."), startupDelay); } } } } else { /* The JVM is down, but a restart has not yet been requested. * See if the user has registered any events for the exit code. */ _sntprintf(onExitParamBuffer, 16 + 10 + 1, TEXT("wrapper.on_exit.%d"), wrapperData->exitCode); onExitAction = getStringProperty(properties, onExitParamBuffer, getStringProperty(properties, TEXT("wrapper.on_exit.default"), TEXT("shutdown"))); if (strcmpIgnoreCase(onExitAction, TEXT("restart")) == 0) { /* We want to restart the JVM. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("on_exit trigger matched. Restarting the JVM. (Exit code: %d)"), wrapperData->exitCode); wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_CONFIGURED; /* Fall through, the restart will take place on the next loop. */ } else if (strcmpIgnoreCase(onExitAction, TEXT("pause")) == 0) { /* We want to pause the JVM. */ if (wrapperData->pausable) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("on_exit trigger matched. Pausing the Wrapper. (Exit code: %d)"), wrapperData->exitCode); wrapperPauseProcess(WRAPPER_ACTION_SOURCE_CODE_ON_EXIT); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("on_exit trigger matched. Pausing not enabled. Restarting the JVM. (Exit code: %d)"), wrapperData->exitCode); wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_CONFIGURED; } } else { /* We want to stop the Wrapper. */ if (strcmpIgnoreCase(onExitAction, TEXT("shutdown")) != 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Encountered an unexpected value for configuration property %s=%s. Resolving to %s."), onExitParamBuffer, onExitAction, TEXT("SHUTDOWN")); } wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } } } else if (wrapperData->wState == WRAPPER_WSTATE_PAUSED) { /* The wrapper is paused. */ if (wrapperData->pausableStopJVM) { /* The stop state is expected. */ /* Make sure we are setup to restart when the Wrapper is resumed later. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_CONFIGURED; } else { /* The JVM should still be running, but it is not. Try to figure out why. */ if (wrapperData->restartRequested) { /* The JVM must have crashed. The restart will be honored when the service * is resumed. Do nothing for now. */ } else { /* No restart was requested. So the JVM must have requested a stop. * Normally, this would result in the service stopping from the paused * state, but it is possible that an exit code is registered. Check them. */ _sntprintf(onExitParamBuffer, 16 + 10 + 1, TEXT("wrapper.on_exit.%d"), wrapperData->exitCode); onExitAction = getStringProperty(properties, onExitParamBuffer, getStringProperty(properties, TEXT("wrapper.on_exit.default"), TEXT("shutdown"))); if (strcmpIgnoreCase(onExitAction, TEXT("restart")) == 0) { /* We want to restart the JVM. But not now. Let the user know. */ log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("on_exit trigger matched. Service is paused, will restart the JVM when resumed. (Exit code: %d)"), wrapperData->exitCode); /* Make sure we are setup to restart when the Wrapper is resumed later. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_CONFIGURED; /* Fall through, the restart will take place once the service is resumed. */ } else if (strcmpIgnoreCase(onExitAction, TEXT("pause")) == 0) { /* We are paused as expected. */ /* Make sure we are setup to restart when the Wrapper is resumed later. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_CONFIGURED; } else { /* We want to stop the Wrapper. */ if (strcmpIgnoreCase(onExitAction, TEXT("shutdown")) != 0) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_WARN, TEXT("Encountered an unexpected value for configuration property %s=%s. Resolving to %d."), onExitParamBuffer, onExitAction, TEXT("SHUTDOWN")); } wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); } } } } else { /* The wrapper is shutting down or pausing. Do nothing. */ } /* Reset the last ping time */ wrapperData->lastPingTicks = nowTicks; wrapperData->lastLoggedPingTicks = nowTicks; } /** * WRAPPER_JSTATE_LAUNCH_DELAY * Waiting to launch a JVM. When the state timeout has expired, a JVM * will be launched. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateLaunchDelay(TICKS nowTicks, int nextSleep) { const TCHAR *mainClass; /* The Waiting state is set from the DOWN_CLEAN state if a JVM had * previously been launched the Wrapper will wait in this state * until the restart delay has expired. If this was the first * invocation, then the state timeout will be set to the current * time causing the new JVM to be launced immediately. */ if ((wrapperData->wState == WRAPPER_WSTATE_STARTING) || (wrapperData->wState == WRAPPER_WSTATE_STARTED) || (wrapperData->wState == WRAPPER_WSTATE_RESUMING)) { /* Is it time to proceed? */ if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { /* Launch the new JVM */ if (wrapperData->jvmRestarts > 0) { /* See if the logs should be rolled on Wrapper startup. */ if (getLogfileRollMode() & ROLL_MODE_JVM) { rollLogs(); } /* Unless this is the first JVM invocation, make it possible to reload the * Wrapper configuration file. */ if (wrapperData->restartReloadConf) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Reloading Wrapper configuration...")); /* If the working dir has been changed then we need to restore it before * the configuration can be reloaded. This is needed to support relative * references to include files. */ if (wrapperData->workingDir && wrapperData->originalWorkingDir) { if (wrapperSetWorkingDir(wrapperData->originalWorkingDir, TRUE)) { /* Failed to restore the working dir. Shutdown the Wrapper */ wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); wrapperData->exitCode = 1; return; } } if (wrapperLoadConfigurationProperties(FALSE)) { /* Failed to reload the configuration. This is bad. * The JVM is already down. Shutdown the Wrapper. */ wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); wrapperData->exitCode = 1; return; } /* Change the working directory if configured to do so. */ if (wrapperData->workingDir && wrapperSetWorkingDir(wrapperData->workingDir, TRUE)) { /* Failed to set the working dir. Shutdown the Wrapper */ wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); wrapperData->exitCode = 1; return; } } } /* Make sure user is not trying to use the old removed SilverEgg package names. */ mainClass = getStringProperty(properties, TEXT("wrapper.java.mainclass"), TEXT("Main")); if (_tcsstr(mainClass, TEXT("com.silveregg.wrapper.WrapperSimpleApp")) != NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s class is no longer supported." ), TEXT("com.silveregg.wrapper.WrapperSimpleApp")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Please use the %s class instead." ), TEXT("com.silveregg.wrapper.WrapperSimpleApp")); wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); wrapperData->exitCode = 1; return; } else if (_tcsstr(mainClass, TEXT("com.silveregg.wrapper.WrapperStartStopApp")) != NULL) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("The %s class is no longer supported." ), TEXT("com.silveregg.wrapper.WrapperStartStopApp")); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Please use the %s class instead." ), TEXT("com.silveregg.wrapper.WrapperStartStopApp")); wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); wrapperData->exitCode = 1; return; } /* Set the launch time to the curent time */ wrapperData->jvmLaunchTicks = nowTicks; /* Generate a unique key to use when communicating with the JVM */ wrapperBuildKey(); /* Check the backend server to make sure it has been initialized. * This is needed so we can pass its port as part of the java command. */ if (!wrapperCheckServerBackend(TRUE)) { /* The backend is not up. An error should have been reported. But this means we * are unable to continue. */ wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); wrapperData->exitCode = 1; return; } /* Generate the command used to launch the Java process */ if (wrapperBuildJavaCommand()) { /* Failed. Wrapper shutdown. */ wrapperSetWrapperState(WRAPPER_WSTATE_STOPPING); wrapperData->exitCode = 1; return; } /* Log a few comments that will explain the JVM behavior. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s wrapper.startup.timeout=%d, wrapper.startup.delay.console=%d, wrapper.startup.delay.service=%d, wrapper.restart.delay=%d"), TEXT("Startup Timeouts:"), wrapperData->startupTimeout, wrapperData->startupDelayConsole, wrapperData->startupDelayService, wrapperData->restartDelay); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s wrapper.ping.interval=%d, wrapper.ping.interval.logged=%d, wrapper.ping.timeout=%d, wrapper.ping.alert.threshold=%d"), TEXT("Ping settings:"), wrapperData->pingInterval, wrapperData->pingIntervalLogged, wrapperData->pingTimeout, wrapperData->pingAlertThreshold); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%s wrapper.shutdown.timeout=%d, wrapper.jvm_exit.timeout=%d, wrapper.jvm_cleanup.timeout=%d, wrapper.jvm_terminate.timeout=%d"), TEXT("Shutdown Timeouts:"), wrapperData->shutdownTimeout, wrapperData->jvmExitTimeout, wrapperData->jvmCleanupTimeout, wrapperData->jvmTerminateTimeout); } if (wrapperData->jvmRestarts > 0) { wrapperSetJavaState(WRAPPER_JSTATE_RESTART, nowTicks, -1); } else { /* Increment the JVM restart Id to keep track of how many JVMs we have launched. */ wrapperData->jvmRestarts++; wrapperSetJavaState(WRAPPER_JSTATE_LAUNCH, nowTicks, -1); } } } else { /* The wrapper is shutting down, pausing or paused. Switch to the * down clean state because the JVM was never launched. */ wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, nowTicks, -1); } } /** * WRAPPER_JSTATE_RESTART * The Wrapper is ready to restart a JVM. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateRestart(TICKS nowTicks, int nextSleep) { if ((wrapperData->wState == WRAPPER_WSTATE_STARTING) || (wrapperData->wState == WRAPPER_WSTATE_STARTED) || (wrapperData->wState == WRAPPER_WSTATE_RESUMING)) { /* Increment the JVM restart Id to keep track of how many JVMs we have launched. */ wrapperData->jvmRestarts++; wrapperSetJavaState(WRAPPER_JSTATE_LAUNCH, nowTicks, -1); } else { /* The wrapper is shutting down, pausing or paused. Switch to the * down clean state because the JVM was never launched. */ wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, nowTicks, -1); } } /** * WRAPPER_JSTATE_LAUNCH * The Wrapper is ready to launch a JVM. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateLaunch(TICKS nowTicks, int nextSleep) { if ((wrapperData->wState == WRAPPER_WSTATE_STARTING) || (wrapperData->wState == WRAPPER_WSTATE_STARTED) || (wrapperData->wState == WRAPPER_WSTATE_RESUMING)) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Launching a JVM...")); if (wrapperExecute()) { /* We know that there was a problem launching the JVM process. * If we fail at this level, assume it is a critical problem and don't bother trying to restart later. * A message should have already been logged. */ wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, nowTicks, -1); } else { /* The JVM was launched. We still do not know whether the * launch will be successful. Allow seconds before giving up. * This can take quite a while if the system is heavily loaded. * (At startup for example) */ if (wrapperData->startupTimeout > 0) { wrapperSetJavaState(WRAPPER_JSTATE_LAUNCHING, nowTicks, wrapperData->startupTimeout); } else { wrapperSetJavaState(WRAPPER_JSTATE_LAUNCHING, nowTicks, -1); } } } else { /* The wrapper is shutting down, pausing or paused. Switch to the down clean state because the JVM was never launched. */ wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, nowTicks, -1); } } /** * WRAPPER_JSTATE_LAUNCHING * The JVM process has been launched, but there has been no confirmation that * the JVM and its application have started. We remain in this state until * the state times out or the WrapperManager class in the JVM has sent a * message that it is initialized. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateLaunching(TICKS nowTicks, int nextSleep) { /* Make sure that the JVM process is still up and running */ if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. Restart it. (Handled and logged) */ } else { /* The process is up and running. * We are waiting in this state until we receive a KEY packet * from the JVM attempting to register. * Have we waited too long already */ if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { if (wrapperData->debugJVM) { handleDebugJVMTimeout(nowTicks, TEXT("Startup: Timed out waiting for a signal from the JVM."), TEXT("startup")); } else { displayLaunchingTimeoutMessage(); /* Give up on the JVM and start trying to kill it. */ wrapperKillProcess(); /* Restart the JVM. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_AUTOMATIC; } } } } /** * WRAPPER_JSTATE_LAUNCHED * The WrapperManager class in the JVM has been initialized. We are now * ready to request that the application in the JVM be started. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateLaunched(TICKS nowTicks, int nextSleep) { int ret; /* The Java side of the wrapper code has responded to a ping. * Tell the Java wrapper to start the Java application. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Start Application.")); } ret = wrapperProtocolFunction(WRAPPER_MSG_START, TEXT("start")); if (ret) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unable to send the start command to the JVM.")); /* Give up on the JVM and start trying to kill it. */ wrapperKillProcess(); /* Restart the JVM. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_AUTOMATIC; } else { /* Start command send. Start waiting for the app to signal * that it has started. Allow seconds before * giving up. A good application will send starting signals back * much sooner than this as a way to extend this time if necessary. */ if (wrapperData->startupTimeout > 0) { wrapperSetJavaState(WRAPPER_JSTATE_STARTING, nowTicks, wrapperData->startupTimeout); } else { wrapperSetJavaState(WRAPPER_JSTATE_STARTING, nowTicks, -1); } } } /** * WRAPPER_JSTATE_STARTING * The JVM is up and the application has been asked to start. We * stay in this state until we receive confirmation that the * application has been started or the state times out. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateStarting(TICKS nowTicks, int nextSleep) { /* Make sure that the JVM process is still up and running */ if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. Restart it. (Handled and logged) */ } else { /* Have we waited too long already */ if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { if (wrapperData->debugJVM) { handleDebugJVMTimeout(nowTicks, TEXT("Startup: Timed out waiting for a signal from the JVM."), TEXT("startup")); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Startup failed: Timed out waiting for signal from JVM.")); /* Give up on the JVM and start trying to kill it. */ wrapperKillProcess(); /* Restart the JVM. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_AUTOMATIC; } } else { /* Keep waiting. */ } } } /** * WRAPPER_JSTATE_STARTED * The application in the JVM has confirmed that it is started. We will * stay in this state, sending pings to the JVM at regular intervals, * until the JVM fails to respond to a ping, or the JVM is ready to be * shutdown. * The pings are sent to make sure that the JVM does not die or hang. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ #define JSTATESTARTED_MESSAGE_MAXLEN (7 + 8 + 1) /* "silent ffffffff\0" */ void jStateStarted(TICKS nowTicks, int nextSleep) { int ret; TCHAR protocolMessage[JSTATESTARTED_MESSAGE_MAXLEN]; PPendingPing pendingPing; /* Make sure that the JVM process is still up and running */ if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. Restart it. (Handled and logged) */ } else { /* Look for any PendingPings which are slow but that we have not yet made a note of. * Don't worry about the posibility of finding more than one in a single pass as that should only happen if the Wrapper process was without CPU for a while. We will quickly catchup on the following cycles. */ if (wrapperData->firstUnwarnedPendingPing != NULL) { if ((wrapperData->pingAlertThreshold > 0) && (wrapperGetTickAgeSeconds(wrapperData->firstUnwarnedPendingPing->slowTicks, nowTicks) >= 0)) { wrapperPingSlow(); /* Remove the PendingPing so it won't be warned again. It still exists in the main list, so it should not be cleaned up here. */ wrapperData->firstUnwarnedPendingPing = wrapperData->firstUnwarnedPendingPing->nextPendingPing; } } if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { /* Have we waited too long already. The jStateTimeoutTicks is reset each time a ping * response is received from the JVM. */ if (wrapperData->debugJVM) { handleDebugJVMTimeout(nowTicks, TEXT("Ping: Timed out waiting for signal from JVM."), TEXT("ping")); } else { if (wrapperData->pingTimedOut == FALSE) { wrapperPingTimeoutResponded(); wrapperData->pingTimedOut = TRUE; } } } else if (wrapperGetTickAgeSeconds(wrapperAddToTicks(wrapperData->lastPingTicks, wrapperData->pingInterval), nowTicks) >= 0) { /* It is time to send another ping to the JVM */ if (wrapperGetTickAgeSeconds(wrapperAddToTicks(wrapperData->lastLoggedPingTicks, wrapperData->pingIntervalLogged), nowTicks) >= 0) { if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: Sending a ping packet.")); } _sntprintf(protocolMessage, JSTATESTARTED_MESSAGE_MAXLEN, TEXT("ping %08x"), nowTicks); ret = wrapperProtocolFunction(WRAPPER_MSG_PING, protocolMessage); wrapperData->lastLoggedPingTicks = nowTicks; } else { if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: Sending a silent ping packet.")); } _sntprintf(protocolMessage, JSTATESTARTED_MESSAGE_MAXLEN, TEXT("silent %08x"), nowTicks); ret = wrapperProtocolFunction(WRAPPER_MSG_PING, protocolMessage); } if (ret) { /* Failed to send the ping. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("JVM Ping Failed.")); } } else { /* Ping sent successfully. */ if (wrapperData->pendingPingQueueOverflow && (!wrapperData->pendingPingQueueOverflowEmptied)) { /* We don't want to create any more PendingPing objects until the JVM has caught up. */ } else if (wrapperData->pendingPingCount >= WRAPPER_MAX_PENDING_PINGS) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Too many Pending Pings. Disabling some ping checks until the JVM has caught up.")); } wrapperData->pendingPingQueueOverflow = TRUE; wrapperData->pendingPingQueueOverflowEmptied = FALSE; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" PING QUEUE Set Overflow")); #endif } else { pendingPing = malloc(sizeof(PendingPing)); if (!pendingPing) { outOfMemory(TEXT("JSS"), 1); } else { memset(pendingPing, 0, sizeof(PendingPing)); pendingPing->sentTicks = nowTicks; pendingPing->timeoutTicks = wrapperAddToTicks(nowTicks, wrapperData->pingTimeout); pendingPing->slowTicks = wrapperAddToTicks(nowTicks, wrapperData->pingAlertThreshold); /* Add it to the PendingPing queue. */ if (wrapperData->firstPendingPing == NULL) { /* The queue was empty. */ wrapperData->pendingPingCount = 1; wrapperData->firstUnwarnedPendingPing = pendingPing; wrapperData->firstPendingPing = pendingPing; wrapperData->lastPendingPing = pendingPing; } else { /* Add to the end of an existing queue. */ wrapperData->pendingPingCount++; if (wrapperData->firstUnwarnedPendingPing == NULL) { wrapperData->firstUnwarnedPendingPing = pendingPing; } wrapperData->lastPendingPing->nextPendingPing = pendingPing; wrapperData->lastPendingPing = pendingPing; } #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("+++ PING QUEUE Size: %d"), wrapperData->pendingPingCount); #endif if ((wrapperData->pendingPingCount > 1) && wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Pending Pings %d"), wrapperData->pendingPingCount); } } } } if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: Sent a ping packet.")); } wrapperData->lastPingTicks = nowTicks; } else { /* Do nothing. Keep waiting. */ } } } /** * WRAPPER_JSTATE_STOP * The application in the JVM should be asked to stop but is still running. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateStop(TICKS nowTicks, int nextSleep) { /* Make sure that the JVM process is still up and running */ if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. (Handled and logged)*/ } else { /* Ask the JVM to shutdown. */ wrapperProtocolFunction(WRAPPER_MSG_STOP, NULL); /* Allow up to 5 + seconds for the application to stop itself. */ if (wrapperData->shutdownTimeout > 0) { wrapperSetJavaState(WRAPPER_JSTATE_STOPPING, nowTicks, 5 + wrapperData->shutdownTimeout); } else { wrapperSetJavaState(WRAPPER_JSTATE_STOPPING, nowTicks, -1); } } } /** * WRAPPER_JSTATE_STOPPING * The application in the JVM has been asked to stop but we are still * waiting for a signal that it is stopped. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateStopping(TICKS nowTicks, int nextSleep) { /* Make sure that the JVM process is still up and running */ if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. (Handled and logged)*/ } else { /* Have we waited too long already */ if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { if (wrapperData->debugJVM) { handleDebugJVMTimeout(nowTicks, TEXT("Shutdown: Timed out waiting for a signal from the JVM."), TEXT("shutdown")); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Shutdown failed: Timed out waiting for signal from JVM.")); /* Give up on the JVM and start trying to kill it. */ wrapperKillProcess(); } } else { /* Keep waiting. */ } } } /** * WRAPPER_JSTATE_STOPPED * The application in the JVM has signalled that it has stopped. We are now * waiting for the JVM process to exit. A good application will do this on * its own, but if it fails to exit in a timely manner then the JVM will be * killed. * Once the JVM process is gone we go back to the DOWN state. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateStopped(TICKS nowTicks, int nextSleep) { if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. This is what we were waiting for. */ } else { /* Have we waited too long already */ if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { if (wrapperData->debugJVM) { handleDebugJVMTimeout(nowTicks, TEXT("Shutdown: Timed out waiting for the JVM to terminate."), TEXT("JVM exit")); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Shutdown failed: Timed out waiting for the JVM to terminate.")); /* Give up on the JVM and start trying to kill it. */ wrapperKillProcess(); } } else { /* Keep waiting. */ } } } /** * WRAPPER_JSTATE_KILLING * The Wrapper is about to kill the JVM. If thread dumps on exit is enabled * then the Wrapper must wait a few moments between telling the JVM to do * a thread dump and actually killing it. The Wrapper will sit in this state * while it is waiting. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateKilling(TICKS nowTicks, int nextSleep) { /* Make sure that the JVM process is still up and running */ if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. (Handled and logged) */ } else { /* Have we waited long enough */ if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { /* It is time to actually kill the JVM. */ wrapperSetJavaState(WRAPPER_JSTATE_KILL, nowTicks, 0); } else { /* Keep waiting. */ } } } /** * WRAPPER_JSTATE_KILL * The Wrapper is ready to kill the JVM. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateKill(TICKS nowTicks, int nextSleep) { if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. (Handled and logged) */ } else { /* Have we waited long enough */ if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { /* It is time to actually kill the JVM. */ if (wrapperKillProcessNow()) { if (wrapperData->restartRequested != WRAPPER_RESTART_REQUESTED_NO) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR,TEXT("Failed to terminate the JVM, abort all restart.")); wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_NO; wrapperData->isRestartDisabled = TRUE; } } else { if (wrapperData->jvmTerminateTimeout > 0) { wrapperSetJavaState(WRAPPER_JSTATE_KILLED, nowTicks, 5 + wrapperData->jvmTerminateTimeout); } else { wrapperSetJavaState(WRAPPER_JSTATE_KILLED, nowTicks, -1); } } } else { /* Keep waiting. */ } } } /** * WRAPPER_JSTATE_KILLED * The Wrapper is ready to kill the JVM. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateKillConfirm(TICKS nowTicks, int nextSleep) { if (nextSleep && (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN)) { /* The process is gone. (Handled and logged) */ } else { if (wrapperData->jStateTimeoutTicksSet && (wrapperGetTickAgeSeconds(wrapperData->jStateTimeoutTicks, nowTicks) >= 0)) { if (wrapperData->restartRequested != WRAPPER_RESTART_REQUESTED_NO) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR,TEXT("Failed to terminate the JVM, abort all restart.")); wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_NO; wrapperData->isRestartDisabled = TRUE; } log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR,TEXT("Failed to terminate the JVM.")); wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CHECK, nowTicks, -1); wrapperStopProcess(1, TRUE); } else { } } } /** * WRAPPER_JSTATE_DOWN_CHECK * The JVM process currently does not exist but we still need to clean up. * Once we have cleaned up, we will switch to the DOWN_FLUSH state. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateDownCheck(TICKS nowTicks, int nextSleep) { wrapperSetJavaState(WRAPPER_JSTATE_DOWN_FLUSH, nowTicks, -1); } /** * WRAPPER_JSTATE_DOWN_FLUSH * The JVM process currently does not exist but we still need to flush all of its output. * Once we have flushed and processed everything, we will switch to the DOWN_CLEAN state. * * nowTicks: The tick counter value this time through the event loop. * nextSleep: Flag which is used to determine whether or not the state engine * will be sleeping before then next time through the loop. It * may make sense to avoid certain actions if it is known that the * function will be called again immediately. */ void jStateDownFlush(TICKS nowTicks, int nextSleep) { PPendingPing pendingPing; /* Always proceed after a single cycle. */ /* TODO - Look into ways of reliably detecting when the backend and stdout piles are closed. */ /* Always close the backend here to make sure we are ready for the next JVM. * In normal cases, the backend will have already been closed, but if the JVM * crashed or the Wrapper thread was delayed, then it is possible that it is * still open at this point. */ wrapperProtocolClose(); /* Make sure that the PendingPing pool is empty so they don't cause strange behavior with the next JVM invocation. */ if (wrapperData->firstPendingPing != NULL) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("%d pings were not replied to when the JVM process exited."), wrapperData->pendingPingCount); } while (wrapperData->firstPendingPing != NULL) { pendingPing = wrapperData->firstPendingPing; if (pendingPing->nextPendingPing != NULL) { /* This was the first PendingPing of several in the queue. */ wrapperData->pendingPingCount--; if (wrapperData->firstUnwarnedPendingPing == wrapperData->firstPendingPing) { wrapperData->firstUnwarnedPendingPing = pendingPing->nextPendingPing; } wrapperData->firstPendingPing = pendingPing->nextPendingPing; pendingPing->nextPendingPing = NULL; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("--- PING QUEUE Size: %d"), wrapperData->pendingPingCount); #endif } else { /* This was the only PendingPing in the queue. */ wrapperData->pendingPingCount = 0; wrapperData->firstUnwarnedPendingPing = NULL; wrapperData->firstPendingPing = NULL; wrapperData->lastPendingPing = NULL; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("--- PING QUEUE Empty.") ); #endif } /* Free up the pendingPing object. */ if (pendingPing != NULL) { free(pendingPing); pendingPing = NULL; } } } if (wrapperData->pendingPingQueueOverflow) { wrapperData->pendingPingQueueOverflow = FALSE; wrapperData->pendingPingQueueOverflowEmptied = FALSE; #ifdef DEBUG_PING_QUEUE log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("--- PING QUEUE Reset Overflow.") ); #endif } /* We are now down and clean. */ wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, nowTicks, -1); } /******************************************************************** * Event Loop / State Engine *******************************************************************/ void logTickTimerStats() { struct tm when; time_t now, overflowTime; TICKS sysTicks; TICKS ticks; time(&now); sysTicks = wrapperGetSystemTicks(); overflowTime = (time_t)(now - (sysTicks / (1000 / WRAPPER_TICK_MS))); when = *localtime(&overflowTime); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Last system time tick overflow at: %04d/%02d/%02d %02d:%02d:%02d"), when.tm_year + 1900, when.tm_mon + 1, when.tm_mday, when.tm_hour, when.tm_min, when.tm_sec); overflowTime = (time_t)(now + ((0xffffffffUL - sysTicks) / (1000 / WRAPPER_TICK_MS))); when = *localtime(&overflowTime); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Next system time tick overflow at: %04d/%02d/%02d %02d:%02d:%02d"), when.tm_year + 1900, when.tm_mon + 1, when.tm_mday, when.tm_hour, when.tm_min, when.tm_sec); if (!wrapperData->useSystemTime) { ticks = wrapperGetTicks(); overflowTime = (time_t)(now - (ticks / (1000 / WRAPPER_TICK_MS))); when = *localtime(&overflowTime); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Last tick overflow at: %04d/%02d/%02d %02d:%02d:%02d"), when.tm_year + 1900, when.tm_mon + 1, when.tm_mday, when.tm_hour, when.tm_min, when.tm_sec); overflowTime = (time_t)(now + ((0xffffffffUL - ticks) / (1000 / WRAPPER_TICK_MS))); when = *localtime(&overflowTime); log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Next tick overflow at: %04d/%02d/%02d %02d:%02d:%02d"), when.tm_year + 1900, when.tm_mon + 1, when.tm_mday, when.tm_hour, when.tm_min, when.tm_sec); } } /** * The main event loop for the wrapper. Handles all state changes and events. */ void wrapperEventLoop() { TICKS nowTicks; int uptimeSeconds; TICKS lastCycleTicks = wrapperGetTicks(); int nextSleep; /* Initialize the tick timeouts. */ wrapperData->anchorTimeoutTicks = lastCycleTicks; wrapperData->commandTimeoutTicks = lastCycleTicks; wrapperData->memoryOutputTimeoutTicks = lastCycleTicks; wrapperData->cpuOutputTimeoutTicks = lastCycleTicks; wrapperData->pageFaultOutputTimeoutTicks = lastCycleTicks; wrapperData->logfileCloseTimeoutTicks = lastCycleTicks; wrapperData->logfileCloseTimeoutTicksSet = FALSE; wrapperData->logfileFlushTimeoutTicks = lastCycleTicks; wrapperData->logfileFlushTimeoutTicksSet = FALSE; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Use tick timer mutex=%s"), wrapperData->useTickMutex ? TEXT("TRUE") : TEXT("FALSE")); } if (wrapperData->isTickOutputEnabled) { logTickTimerStats(); } if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Event loop started.")); } if (wrapperData->isMemoryOutputEnabled) { wrapperDumpMemoryBanner(); } nextSleep = TRUE; do { if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: %ssleep"), (nextSleep ? TEXT("") : TEXT("no "))); } if (nextSleep) { /* Sleep for a tenth of a second. */ wrapperSleep(100); } nextSleep = TRUE; /* Before doing anything else, always maintain the logger to make sure * that any queued messages are logged before doing anything else. * Called a second time after socket and child output to make sure * that all messages appropriate for the state changes have been * logged. Failure to do so can result in a confusing sequence of * output. */ if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: maintain logger")); } maintainLogger(); if (wrapperData->pauseThreadMain) { wrapperPauseThread(wrapperData->pauseThreadMain, TEXT("main")); wrapperData->pauseThreadMain = 0; } /* After we maintain the logger, see if there were any signals trapped. */ #ifdef WIN32 wrapperMaintainControlCodes(); #else wrapperMaintainSignals(); #endif #ifdef WIN32 /* Check to make sure the Wrapper or Java console windows are hidden. * This is done here to make sure they go away even in cases where they can't be hidden right away. * Users have also reported that the console can be redisplayed when a user logs back in or switches users. */ wrapperCheckConsoleWindows(); #endif if (!wrapperData->useJavaIOThread) { /* Check the stout pipe of the child process. */ if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: process JVM output")); } /* Request that the processing of child output not take more than 250ms. */ if (wrapperReadChildOutput(250)) { if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Pause reading child process output to share cycles.")); } nextSleep = FALSE; } } /* Check for incoming data packets. */ if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: process socket")); } /* Don't bother processing the socket if we are shutting down and the JVM is down. */ if (((wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN)) && ((wrapperData->wState == WRAPPER_WSTATE_STOPPING) || (wrapperData->wState == WRAPPER_WSTATE_STOPPED))) { /* Skip socket processing. */ } else { if (wrapperProtocolRead()) { /* There was more data waiting to be read, but we broke out. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Pause reading socket data to share cycles.")); } nextSleep = FALSE; } } /* See comment for first call above. */ if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: maintain logger(2)")); } maintainLogger(); /* Get the current time for use in this cycle. */ nowTicks = wrapperGetTicks(); /* Tell the logging code what to use for the uptime. */ if (!wrapperData->uptimeFlipped) { uptimeSeconds = wrapperGetTickAgeSeconds(WRAPPER_TICK_INITIAL, nowTicks); if (uptimeSeconds > WRAPPER_MAX_UPTIME_SECONDS) { wrapperData->uptimeFlipped = TRUE; setUptime(0, TRUE); } else { setUptime(uptimeSeconds, FALSE); } } /* Log memory usage. */ if (wrapperData->isMemoryOutputEnabled) { if (wrapperTickExpired(nowTicks, wrapperData->memoryOutputTimeoutTicks)) { wrapperDumpMemory(); wrapperData->memoryOutputTimeoutTicks = wrapperAddToTicks(nowTicks, wrapperData->memoryOutputInterval); } } /* Log CPU usage. */ if (wrapperData->isCPUOutputEnabled) { if (wrapperTickExpired(nowTicks, wrapperData->cpuOutputTimeoutTicks)) { wrapperDumpCPUUsage(); wrapperData->cpuOutputTimeoutTicks = wrapperAddToTicks(nowTicks, wrapperData->cpuOutputInterval); } } #ifdef WIN32 /* Log PageFault info. */ if (wrapperData->isPageFaultOutputEnabled) { if (wrapperTickExpired(nowTicks, wrapperData->pageFaultOutputTimeoutTicks)) { wrapperDumpPageFaultUsage(); wrapperData->pageFaultOutputTimeoutTicks = wrapperAddToTicks(nowTicks, wrapperData->pageFaultOutputInterval); } } #endif /* Test the activity of the logfile. */ if (getLogfileActivity() != 0) { /* There was log output since the last pass. */ /* Set the close timeout if enabled. This is based on inactivity, so we always want to extend it from the current time when there was output. */ if (wrapperData->logfileCloseTimeout > 0) { wrapperData->logfileCloseTimeoutTicks = wrapperAddToTicks(nowTicks, wrapperData->logfileCloseTimeout); wrapperData->logfileCloseTimeoutTicksSet = TRUE; } /* Set the flush timeout if enabled, and it is not already set. */ if (wrapperData->logfileFlushTimeout > 0) { if (!wrapperData->logfileFlushTimeoutTicksSet) { wrapperData->logfileFlushTimeoutTicks = wrapperAddToTicks(nowTicks, wrapperData->logfileFlushTimeout); wrapperData->logfileFlushTimeoutTicksSet = TRUE; } } } else if (wrapperData->logfileCloseTimeoutTicksSet && (wrapperTickExpired(nowTicks, wrapperData->logfileCloseTimeoutTicks))) { /* If the inactivity timeout has expired then we want to close the logfile, otherwise simply flush it. */ closeLogfile(); /* Reset the timeout ticks so we don't start another timeout until something has been logged. */ wrapperData->logfileCloseTimeoutTicksSet = FALSE; /* If we close the file, it is automatically flushed. */ wrapperData->logfileFlushTimeoutTicksSet = FALSE; } /* Is it is time to flush the logfile? */ if (wrapperData->logfileFlushTimeoutTicksSet && (wrapperTickExpired(nowTicks, wrapperData->logfileFlushTimeoutTicks))) { /* Time to flush the output. */ flushLogfile(); /* Reset the timeout until more output is logged. */ wrapperData->logfileFlushTimeoutTicksSet = FALSE; } /* Has the process been getting CPU? This check will only detect a lag * if the useSystemTime flag is set. */ if (wrapperGetTickAgeSeconds(lastCycleTicks, nowTicks) > wrapperData->cpuTimeout) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_INFO, TEXT("Wrapper Process has not received any CPU time for %d seconds. Extending timeouts."), wrapperGetTickAgeSeconds(lastCycleTicks, nowTicks)); if (wrapperData->jStateTimeoutTicksSet) { wrapperData->jStateTimeoutTicks = wrapperAddToTicks(wrapperData->jStateTimeoutTicks, wrapperGetTickAgeSeconds(lastCycleTicks, nowTicks)); } } lastCycleTicks = nowTicks; /* Useful for development debugging, but not runtime debugging */ if (wrapperData->isStateOutputEnabled) { if (wrapperData->jStateTimeoutTicksSet) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Ticks=%08x, WrapperState=%s, JVMState=%s JVMStateTimeoutTicks=%08x (%ds), Exit=%s, RestartMode=%d"), nowTicks, wrapperGetWState(wrapperData->wState), wrapperGetJState(wrapperData->jState), wrapperData->jStateTimeoutTicks, wrapperGetTickAgeSeconds(nowTicks, wrapperData->jStateTimeoutTicks), (wrapperData->exitRequested ? TEXT("true") : TEXT("false")), wrapperData->restartRequested); } else { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Ticks=%08x, WrapperState=%s, JVMState=%s JVMStateTimeoutTicks=%08x (N/A), Exit=%s, RestartMode=%d"), nowTicks, wrapperGetWState(wrapperData->wState), wrapperGetJState(wrapperData->jState), wrapperData->jStateTimeoutTicks, (wrapperData->exitRequested ? TEXT("true") : TEXT("false")), wrapperData->restartRequested); } } /* If we are configured to do so, confirm that the anchor file still exists. */ anchorPoll(nowTicks); /* If we are configured to do so, look for a command file and perform any * requested operations. */ commandPoll(nowTicks); if (wrapperData->exitRequested) { /* A new request for the JVM to be stopped has been made. */ if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: exit requested")); } /* Acknowledge that we have seen the exit request so we don't get here again. */ wrapperData->exitRequested = FALSE; if (wrapperData->jState == WRAPPER_JSTATE_DOWN_CLEAN) { /* A JVM is not currently running. Nothing to do.*/ } else if ((wrapperData->jState == WRAPPER_JSTATE_LAUNCH_DELAY) || (wrapperData->jState == WRAPPER_JSTATE_RESTART) || (wrapperData->jState == WRAPPER_JSTATE_LAUNCH)) { /* A JVM is not yet running go back to the DOWN_CLEAN state. */ wrapperSetJavaState(WRAPPER_JSTATE_DOWN_CLEAN, nowTicks, -1); } else if ((wrapperData->jState == WRAPPER_JSTATE_STOP) || (wrapperData->jState == WRAPPER_JSTATE_STOPPING) || (wrapperData->jState == WRAPPER_JSTATE_STOPPED) || (wrapperData->jState == WRAPPER_JSTATE_KILLING) || (wrapperData->jState == WRAPPER_JSTATE_KILL) || (wrapperData->jState == WRAPPER_JSTATE_KILLED) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_CHECK) || (wrapperData->jState == WRAPPER_JSTATE_DOWN_FLUSH)) { /* The JVM is already being stopped, so nothing else needs to be done. */ } else { /* The JVM should be running or is in the process of launching, so it needs to be stopped. */ if (wrapperGetProcessStatus(nowTicks, FALSE) == WRAPPER_PROCESS_DOWN) { /* The process is gone. (Handled and logged) */ if (wrapperData->restartPacketReceived) { /* The restart packet was received. If we are here then it was delayed, * but it means that we do want to restart. */ } else { /* We never want to restart here. */ wrapperData->restartRequested = WRAPPER_RESTART_REQUESTED_NO; if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Reset the restart flag.")); } } } else { /* JVM is still up. Try asking it to shutdown nicely. */ if (wrapperData->isDebugging) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_DEBUG, TEXT("Sending stop signal to JVM")); } wrapperSetJavaState(WRAPPER_JSTATE_STOP, nowTicks, -1); } } } /* Do something depending on the wrapper state */ if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: handle wrapper state: %s"), wrapperGetWState(wrapperData->wState)); } switch(wrapperData->wState) { case WRAPPER_WSTATE_STARTING: wStateStarting(nowTicks); break; case WRAPPER_WSTATE_STARTED: wStateStarted(nowTicks); break; case WRAPPER_WSTATE_PAUSING: wStatePausing(nowTicks); break; case WRAPPER_WSTATE_PAUSED: wStatePaused(nowTicks); break; case WRAPPER_WSTATE_RESUMING: wStateResuming(nowTicks); break; case WRAPPER_WSTATE_STOPPING: wStateStopping(nowTicks); break; case WRAPPER_WSTATE_STOPPED: wStateStopped(nowTicks); break; default: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unknown wState=%d"), wrapperData->wState); break; } /* Do something depending on the JVM state */ if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT(" Loop: handle JVM state: %s"), wrapperGetJState(wrapperData->jState)); } switch(wrapperData->jState) { case WRAPPER_JSTATE_DOWN_CLEAN: jStateDownClean(nowTicks, nextSleep); break; case WRAPPER_JSTATE_LAUNCH_DELAY: jStateLaunchDelay(nowTicks, nextSleep); break; case WRAPPER_JSTATE_RESTART: jStateRestart(nowTicks, nextSleep); break; case WRAPPER_JSTATE_LAUNCH: jStateLaunch(nowTicks, nextSleep); break; case WRAPPER_JSTATE_LAUNCHING: jStateLaunching(nowTicks, nextSleep); break; case WRAPPER_JSTATE_LAUNCHED: jStateLaunched(nowTicks, nextSleep); break; case WRAPPER_JSTATE_STARTING: jStateStarting(nowTicks, nextSleep); break; case WRAPPER_JSTATE_STARTED: jStateStarted(nowTicks, nextSleep); break; case WRAPPER_JSTATE_STOP: jStateStop(nowTicks, nextSleep); break; case WRAPPER_JSTATE_STOPPING: jStateStopping(nowTicks, nextSleep); break; case WRAPPER_JSTATE_STOPPED: jStateStopped(nowTicks, nextSleep); break; case WRAPPER_JSTATE_KILLING: jStateKilling(nowTicks, nextSleep); break; case WRAPPER_JSTATE_KILL: jStateKill(nowTicks, nextSleep); break; case WRAPPER_JSTATE_KILLED: jStateKillConfirm(nowTicks, nextSleep); break; case WRAPPER_JSTATE_DOWN_CHECK: jStateDownCheck(nowTicks, nextSleep); break; case WRAPPER_JSTATE_DOWN_FLUSH: jStateDownFlush(nowTicks, nextSleep); break; default: log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_ERROR, TEXT("Unknown jState=%d"), wrapperData->jState); break; } } while (wrapperData->wState != WRAPPER_WSTATE_STOPPED); /* Assertion check of Java State. */ if (wrapperData->jState != WRAPPER_JSTATE_DOWN_CLEAN) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_FATAL, TEXT("Wrapper shutting down while java state still %s."), wrapperGetJState(wrapperData->jState)); } if (wrapperData->isLoopOutputEnabled) { log_printf(WRAPPER_SOURCE_WRAPPER, LEVEL_STATUS, TEXT("Event loop stopped.")); } } wrapper_3.5.26_src/src/c/wrapperinfo.c.in100644 0 0 2162 12440202301 15452 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.org/doc/english/licenseOverview.html */ #ifdef WIN32 #include #include #endif #include "wrapper_i18n.h" /** * wrapperinfo.c is built as part of the build process. Ant creates this * file by making a copy of wrapperinfo.c.in, replacing tokens as it does * so. If you need to make modifications to this file, the changes should * always be made to wrapperinfo.c.in. */ TCHAR *wrapperVersionRoot = TEXT("@version.root@"); TCHAR *wrapperVersion = TEXT("@version@"); TCHAR *wrapperBits = TEXT("@bits@"); TCHAR *wrapperArch = TEXT("@dist.arch@"); TCHAR *wrapperOS = TEXT("@dist.os@"); TCHAR *wrapperReleaseDate = TEXT("20141205"); TCHAR *wrapperReleaseTime = TEXT("0000"); TCHAR *wrapperBuildDate = TEXT("@build.date@"); TCHAR *wrapperBuildTime = TEXT("@build.time@"); wrapper_3.5.26_src/src/c/wrapperinfo.h100644 0 0 1354 12440202301 15054 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ #ifndef _WRAPPERINFO_H #define _WRAPPERINFO_H #ifdef WIN32 #include #endif extern TCHAR *wrapperVersionRoot; extern TCHAR *wrapperVersion; extern TCHAR *wrapperBits; extern TCHAR *wrapperArch; extern TCHAR *wrapperOS; extern TCHAR *wrapperReleaseDate; extern TCHAR *wrapperReleaseTime; extern TCHAR *wrapperBuildDate; extern TCHAR *wrapperBuildTime; #endif wrapper_3.5.26_src/src/c/wrapperjni.c100644 0 0 70407 12440202301 14721 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ #include #include #include #include #include #ifdef WIN32 #include #include #include #define dup2 _dup2 #endif #include "wrapper_i18n.h" #include "loggerjni.h" #include "wrapperjni.h" #include "wrapperinfo.h" /* The largest possible "name+'='+value" property pair length on Windows. */ #define MAX_ENV_PAIR_LEN 32767 int wrapperJNIDebugging = JNI_FALSE; #define CONTROL_EVENT_QUEUE_SIZE 10 int controlEventQueue[CONTROL_EVENT_QUEUE_SIZE]; int controlEventQueueLastReadIndex = 0; int controlEventQueueLastWriteIndex = 0; /** Flag to keep track of whether StdOut has been redirected. */ int redirectedStdOut = FALSE; /** Flag to keep track of whether StdErr has been redirected. */ int redirectedStdErr = FALSE; /* Special symbols that need to be defined manually as part of the bootstrap process. */ const char utf8ClassJavaLangString[] = {106, 97,118, 97, 47, /* java/ */ 108, 97,110,103, 47, /* lang/ */ 83,116,114,105,110,103, 0}; /* "java/lang/String" */ const char utf8MethodInit[] = {60,105,110,105,116, 62, 0}; /* "" */ const char utf8Sig_BrV[] = {40, 91, 66, 41, 86, 0}; /* "([B)V" */ const char utf8Sigr_B[] = { 40, 41, 91, 66, 0}; /* "()[B") */ const char utf8MethodGetBytes[] = {103, 101, 116, 66, 121, 116, 101, 115, 0}; /* getBytes */ const char utf8ClassJavaLangOutOfMemoryError[] = {106, 97,118, 97, 47, /* java/ */ 108, 97,110, 103, 47, /* lang/ */ 79, 117, 116, 79, 102, 77, 101, 109, 111, 114, 121, 69, 114, 114, 111, 114, 0}; /* OutOfMemoryError */ const char utf8ClassOrgTanukisoftwareWrapperWrapperJNIError[] = {111, 114, 103, 47, /* org/ */ 116, 97, 110, 117, 107, 105, 115, 111, 102, 116, 119, 97, 114, 101, 47, /* tanukisoftware/ */ 119, 114, 97, 112, 112, 101, 114, 47, /* wrapper/ */ 87, 114, 97, 112, 112, 101, 114, 74, 78, 73, 69, 114, 114, 111, 114, 0}; /* "WrapperJNIError" */ /* * For UTF8 constants, '_' in the name means an array, 'r' preceeds the return * portion of a method declaration, 'V' is Void. The rest is like the * Java format. */ char *utf8SigLjavaLangStringrV; char *utf8ClassJavaLangSystem; char *utf8MethodGetProperties; char *utf8SigVrLjavaUtilProperties; char *utf8MethodGetProperty; char *utf8SigLjavaLangStringrLjavaLangString; char *utf8javaIOIOException; /* "java/io/IOException" */ #ifdef WIN32 #else char *utf8ClassOrgTanukisoftwareWrapperWrapperUNIXUser; char *utf8MethodSetGroup; char *utf8MethodAddGroup; char *utf8SigIIStringStringStringStringrV; char *utf8SigIStringrV; #endif /** * Cause the current thread to sleep for the specified number of milliseconds. * Sleeps over one second are not allowed. * * @param ms Number of milliseconds to wait for. * * @return TRUE if the was interrupted, FALSE otherwise. Neither is an error. */ int wrapperSleep(int ms) { #ifdef WIN32 Sleep(ms); #else /* We want to use nanosleep if it is available, but make it possible for the user to build a version that uses usleep if they want. usleep does not behave nicely with signals thrown while sleeping. This was the believed cause of a hang experienced on one Solaris system. */ #ifdef USE_USLEEP usleep(ms * 1000); /* microseconds */ #else struct timespec ts; if (ms >= 1000) { ts.tv_sec = (ms * 1000000) / 1000000000; ts.tv_nsec = (ms * 1000000) % 1000000000; /* nanoseconds */ } else { ts.tv_sec = 0; ts.tv_nsec = ms * 1000000; /* nanoseconds */ } if (nanosleep(&ts, NULL)) { if (errno == EINTR) { return TRUE; } else if (errno == EAGAIN) { return TRUE; } } #endif #endif return FALSE; } /** * Create a jstring from a Wide Char string. The jstring must be freed up by caller. * * @param env The current JNIEnv. * @param strW The Wide string to convert. * * @return The new jstring or NULL if there were any exceptions thrown. */ jstring JNU_NewStringNative(JNIEnv *env, const TCHAR *strW) { jstring result; jclass jClassString; jmethodID MID_String_init; jbyteArray jBytes; size_t len; char* msgMB; #ifdef UNICODE int size; #endif #ifdef UNICODE /* We need to special case empty strings as some of the functions don't work correctly for them. */ len = _tcslen(strW); if (len > 0) { #ifdef WIN32 size = WideCharToMultiByte(CP_UTF8, 0, strW, -1, NULL, 0, NULL, NULL); if (size == 0) { /* Failed. */ _tprintf(TEXT("WrapperJNI Warn: Failed to convert string \"%s\": %s\n"), strW, getLastErrorText()); fflush(NULL); return NULL; } msgMB = malloc(sizeof(char) * (size + 1)); if (!msgMB) { throwOutOfMemoryError(env, TEXT("JNSN1")); return NULL; } WideCharToMultiByte(CP_UTF8, 0, strW, -1, msgMB, size + 1, NULL, NULL); result = (*env)->NewStringUTF(env, msgMB); free(msgMB); return result; #else size = wcstombs(NULL, strW, 0); if (size == (size_t)-1) { _tprintf(TEXT("Invalid multibyte sequence \"%s\": %s\n"), strW, getLastErrorText()); return NULL; } msgMB = malloc(sizeof(char) * (size + 1)); if (!msgMB) { throwOutOfMemoryError(env, TEXT("JNSN2")); return NULL; } wcstombs(msgMB, strW, size + 1); #endif } else { /* Empty string. */ msgMB = malloc(sizeof(char) * 1); if (!msgMB) { throwOutOfMemoryError(env, TEXT("JNSN3")); return NULL; } msgMB[0] = '\0'; } #else msgMB = (TCHAR*)strW; #endif result = NULL; if ((*env)->EnsureLocalCapacity(env, 2) < 0) { throwOutOfMemoryError(env, TEXT("JNSN4")); #ifdef UNICODE if (msgMB) { free(msgMB); } #endif return NULL; /* out of memory error */ } len = strlen(msgMB); if ((jBytes = (*env)->NewByteArray(env, (jsize)len))) { (*env)->SetByteArrayRegion(env, jBytes, 0, (jsize)len, (jbyte*)msgMB); if ((jClassString = (*env)->FindClass(env, utf8ClassJavaLangString))) { if ((MID_String_init = (*env)->GetMethodID(env, jClassString, utf8MethodInit, utf8Sig_BrV))) { result = (*env)->NewObject(env, jClassString, MID_String_init, jBytes); } (*env)->DeleteLocalRef(env, jClassString); } (*env)->DeleteLocalRef(env, jBytes); } #ifdef UNICODE if (msgMB) { free(msgMB); } #endif return result; } #ifdef WIN32 /* So far this function is only used by windows. if we want to use it for unix as well, first provide correct wchar handling... */ void JNU_SetByteArrayRegion(JNIEnv *env, jbyteArray* jarray, jsize start, jsize len, const TCHAR *buffer) { char* msg; #if defined(UNICODE) && defined(WIN32) int size; size = WideCharToMultiByte(CP_OEMCP, 0, buffer, -1, NULL, 0, NULL, NULL); msg = malloc(size); if (!msg) { throwOutOfMemoryError(env, TEXT("JSBAR1")); return; } WideCharToMultiByte(CP_OEMCP,0, buffer,-1, msg, size, NULL, NULL); #else msg = (TCHAR*) buffer; #endif (*env)->SetByteArrayRegion(env, *jarray, start, len, (jbyte*) msg); #if defined(UNICODE) && defined(WIN32) free(msg); #endif } #endif /** * Converts a jstring into a newly malloced TCHAR array. * * @param end The JNIEnv. * @param jstr The jstring. * * @return The requested Wide String, or NULL if there was a problem. It is * the responsibility of the caller to free up the returned string. */ TCHAR *JNU_GetStringNativeChars(JNIEnv *env, jstring jstr) { jbyteArray jByteArrayBytes = 0; jclass jClassString = NULL; jmethodID jMethodIdStringGetBytes = NULL; #ifdef UNICODE int size; TCHAR* tresult; #endif char *result = 0; if ((*env)->EnsureLocalCapacity(env, 2) < 0) { throwOutOfMemoryError(env, TEXT("GSNC1")); return NULL; /* out of memory error */ } if ((jClassString = (*env)->FindClass(env, utf8ClassJavaLangString)) != NULL) { if ((jMethodIdStringGetBytes = (*env)->GetMethodID(env, jClassString, utf8MethodGetBytes, utf8Sigr_B)) != NULL) { if ((jByteArrayBytes = (*env)->CallObjectMethod(env, jstr, jMethodIdStringGetBytes)) != NULL) { jint len = (*env)->GetArrayLength(env, jByteArrayBytes); result = (char *)malloc(sizeof(char) * (len + 1)); if (!result) { throwOutOfMemoryError(env, TEXT("GSNC2")); } else { (*env)->GetByteArrayRegion(env, jByteArrayBytes, 0, len, (jbyte *)result); result[len] = 0; /* NULL-terminate */ } (*env)->DeleteLocalRef(env, jByteArrayBytes); } } (*env)->DeleteLocalRef(env, jClassString); } #ifdef UNICODE #ifdef WIN32 size = MultiByteToWideChar(CP_OEMCP, 0, result, -1, NULL, 0); tresult = malloc(size*sizeof(LPWSTR)); if (!tresult) { free(result); throwOutOfMemoryError(env, TEXT("GSNC3")); return NULL; } MultiByteToWideChar(CP_OEMCP, 0, result,-1, tresult, size); free(result); return tresult; #else size = mbstowcs(NULL, result, MBSTOWCS_QUERY_LENGTH); if (size == (size_t)-1) { throwJNIError(env, TEXT("Encoding error.")); return NULL; } tresult = malloc(sizeof(TCHAR) * (size + 1)); if (!tresult) { free(result); throwOutOfMemoryError(env, TEXT("GSNC3")); return NULL; } mbstowcs(tresult, result, size + 1); tresult[size] = TEXT('\0'); /* Avoid bufferflows caused by badly encoded characters. */ free(result); return tresult; #endif #else return result; #endif } jstring JNU_NewStringFromNativeChar(JNIEnv *env, const char *str) { jstring result; jclass jClassString; jmethodID MID_String_init; jbyteArray bytes = 0; size_t len; result = NULL; if ((*env)->EnsureLocalCapacity(env, 2) < 0) { throwOutOfMemoryError(env, TEXT("JNSN2")); return NULL; /* out of memory error */ } len = strlen(str); bytes = (*env)->NewByteArray(env, (jsize)len); if (bytes != NULL) { (*env)->SetByteArrayRegion(env, bytes, 0, (jsize)len,(jbyte*) str); if ((jClassString = (*env)->FindClass(env, utf8ClassJavaLangString)) != NULL) { if ((MID_String_init = (*env)->GetMethodID(env, jClassString, utf8MethodInit, utf8Sig_BrV)) != NULL) { result = (*env)->NewObject(env, jClassString, MID_String_init, bytes); } (*env)->DeleteLocalRef(env, jClassString); } (*env)->DeleteLocalRef(env, bytes); } /* else fall through */ return result; } /** * Returns a new buffer containing the UTF8 characters for the specified native string. * * It is the responsibility of the caller to free the returned buffer. */ char *getUTF8Chars(JNIEnv *env, const char *nativeChars) { jstring js; jsize jlen; const char *stringChars; jboolean isCopy; char *utf8Chars = NULL; js = JNU_NewStringFromNativeChar(env, nativeChars); if (js != NULL) { jlen = (*env)->GetStringUTFLength(env, js); utf8Chars = malloc(jlen + 1); if (!utf8Chars) { throwOutOfMemoryError(env, TEXT("GUTFC1")); } else { stringChars = ((*env)->GetStringUTFChars(env, js, &isCopy)); if (stringChars != NULL) { memcpy(utf8Chars, stringChars, jlen); utf8Chars[jlen] = '\0'; (*env)->ReleaseStringUTFChars(env, js, stringChars); } else { throwOutOfMemoryError(env, TEXT("GUTFC2")); free(utf8Chars); utf8Chars = NULL; } } (*env)->DeleteLocalRef(env, js); } return utf8Chars; } void initUTF8Strings(JNIEnv *env) { /* Now initialize all of the strings using our helper function. */ utf8SigLjavaLangStringrV = getUTF8Chars(env, "(Ljava/lang/String;)V"); utf8ClassJavaLangSystem = getUTF8Chars(env, "java/lang/System"); utf8MethodGetProperties = getUTF8Chars(env, "getProperties"); utf8SigVrLjavaUtilProperties = getUTF8Chars(env, "()Ljava/util/Properties;"); utf8MethodGetProperty = getUTF8Chars(env, "getProperty"); utf8SigLjavaLangStringrLjavaLangString = getUTF8Chars(env, "(Ljava/lang/String;)Ljava/lang/String;"); utf8javaIOIOException = getUTF8Chars(env, "java/io/IOException"); #ifdef WIN32 #else utf8ClassOrgTanukisoftwareWrapperWrapperUNIXUser = getUTF8Chars(env, "org/tanukisoftware/wrapper/WrapperUNIXUser"); utf8MethodSetGroup = getUTF8Chars(env, "setGroup"); utf8MethodAddGroup = getUTF8Chars(env, "addGroup"); utf8SigIIStringStringStringStringrV = getUTF8Chars(env, "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); utf8SigIStringrV = getUTF8Chars(env, "(ILjava/lang/String;)V"); #endif } /** * Looks up a System property and sets its value in the propertyValue parameter. * * It is the responsibility of the caller to free up the propertyValue buffer if it is non-NULL. * * @param env Current JNIEnv. * @param propertyName Name of the property. * @param propertyValue Value of the property, or NULL if it was not set. * * @return TRUE if there were any problems, FALSE if successful. NULL values will still be successful. */ int getSystemProperty(JNIEnv *env, const TCHAR *propertyName, TCHAR **propertyValue, int encodeNative) { int result; jclass jClassSystem; jmethodID jMethodIdGetProperty; jstring jStringKeyPropName; jstring jStringKeyValue; TCHAR *keyChars; /* Initialize the propertyValue to point to NULL in case we fail. */ *propertyValue = NULL; if ((jClassSystem = (*env)->FindClass(env, utf8ClassJavaLangSystem)) != NULL) { if ((jMethodIdGetProperty = (*env)->GetStaticMethodID(env, jClassSystem, utf8MethodGetProperty, utf8SigLjavaLangStringrLjavaLangString)) != NULL) { if ((jStringKeyPropName = JNU_NewStringNative(env, propertyName)) != NULL) { if ((jStringKeyValue = (jstring)(*env)->CallStaticObjectMethod(env, jClassSystem, jMethodIdGetProperty, jStringKeyPropName)) != NULL) { /* Collect the value. */ if (!encodeNative) { if ((keyChars = JNU_GetStringNativeChars(env, jStringKeyValue)) != NULL) { *propertyValue = malloc(sizeof(TCHAR) * (_tcslen(keyChars) + 1)); if (!*propertyValue) { throwOutOfMemoryError(env, TEXT("GSP1")); result = TRUE; } else { _tcsncpy(*propertyValue, keyChars, _tcslen(keyChars) + 1); result = FALSE; } free(keyChars); } else { /* Exception Thrown */ result = TRUE; } } else { if ((keyChars = (TCHAR*)(*env)->GetStringUTFChars(env, jStringKeyValue, NULL)) != NULL) { *propertyValue = malloc(strlen((char*)keyChars) + 1); if (!*propertyValue) { throwOutOfMemoryError(env, TEXT("GSP2")); result = TRUE; } else { strncpy((char*)*propertyValue, (char*)keyChars, strlen((char*)keyChars) + 1); result = FALSE; } (*env)->ReleaseStringUTFChars(env, jStringKeyValue, (const char *)keyChars); } else { /* Exception Thrown */ result = TRUE; } } (*env)->DeleteLocalRef(env, jStringKeyValue); } else { /* Property was not set. */ result = FALSE; } (*env)->DeleteLocalRef(env, jStringKeyPropName); } else { result = TRUE; } } else { result = TRUE; } (*env)->DeleteLocalRef(env, jClassSystem); } else { result = TRUE; } return result; } /** * Do common initializaion. * * @return TRUE if there were any problems. */ int initCommon(JNIEnv *env, jclass jClassWrapperManager) { TCHAR* outfile; TCHAR* errfile; int outfd; int errfd; int mode; int options; #ifdef WIN32 mode = _S_IWRITE; options = _O_WRONLY | _O_APPEND | _O_CREAT; #else mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; options = O_WRONLY | O_APPEND | O_CREAT; #endif initUTF8Strings(env); if (getSystemProperty(env, TEXT("wrapper.java.errfile"), &errfile, FALSE)) { /* Failed */ return TRUE; } if (errfile) { _ftprintf(stderr, TEXT("WrapperJNI: Redirecting %s to file %s...\n"), TEXT("StdErr"), errfile); fflush(NULL); if (((errfd = _topen(errfile, options, mode)) == -1) || (dup2(errfd, STDERR_FILENO) == -1)) { throwThrowable(env, utf8javaIOIOException, TEXT("Failed to redirect %s to file %s (Err: %s)"), TEXT("StdErr"), errfile, getLastErrorText()); return TRUE; } else { redirectedStdErr = TRUE; } } if (getSystemProperty(env, TEXT("wrapper.java.outfile"), &outfile, FALSE)) { /* Failed */ return TRUE; } if (outfile) { _tprintf(TEXT("WrapperJNI: Redirecting %s to file %s...\n"), TEXT("StdOut"), outfile); fflush(NULL); if (((outfd = _topen(outfile, options, mode)) == -1) || (dup2(outfd, STDOUT_FILENO) == -1)) { throwThrowable(env, utf8javaIOIOException, TEXT("Failed to redirect %s to file %s (Err: %s)"), TEXT("StdOut"), outfile, getLastErrorText()); return TRUE; } else { redirectedStdOut = TRUE; } } return FALSE; } void throwThrowable(JNIEnv *env, char *throwableClassName, const TCHAR *lpszFmt, ...) { va_list vargs; int messageBufferSize = 0; TCHAR *messageBuffer = NULL; int count; jclass jThrowableClass; jmethodID constructor; jstring jMessageBuffer; jobject jThrowable; do { if (messageBufferSize == 0) { /* No buffer yet. Allocate one to get started. */ messageBufferSize = 100; #if defined(HPUX) /* Due to a bug in the HPUX libc (version < 1403), the length of the buffer passed to _vsntprintf must have a length of 1 + N, where N is a multiple of 8. Adjust it as necessary. */ messageBufferSize = messageBufferSize + (((messageBufferSize - 1) % 8) == 0 ? 0 : 8 - ((messageBufferSize - 1) % 8)); #endif messageBuffer = (TCHAR*)malloc( messageBufferSize * sizeof(TCHAR)); if (!messageBuffer) { throwOutOfMemoryError(env, TEXT("TT1")); return; } } /* Try writing to the buffer. */ va_start(vargs, lpszFmt); count = _vsntprintf(messageBuffer, messageBufferSize, lpszFmt, vargs); va_end(vargs); if ((count < 0) || (count >= (int)messageBufferSize)) { /* If the count is exactly equal to the buffer size then a null TCHAR was not written. * It must be larger. * Windows will return -1 if the buffer is too small. If the number is * exact however, we still need to expand it to have room for the null. * UNIX will return the required size. */ /* Free the old buffer for starters. */ free(messageBuffer); /* Decide on a new buffer size. */ if (count <= (int)messageBufferSize) { messageBufferSize += 50; } else if (count + 1 <= (int)messageBufferSize + 50) { messageBufferSize += 50; } else { messageBufferSize = count + 1; } #if defined(HPUX) /* Due to a bug in the HPUX libc (version < 1403), the length of the buffer passed to _vsntprintf must have a length of 1 + N, where N is a multiple of 8. Adjust it as necessary. */ messageBufferSize = messageBufferSize + (((messageBufferSize - 1) % 8) == 0 ? 0 : 8 - ((messageBufferSize - 1) % 8)); #endif messageBuffer = (TCHAR*)malloc(messageBufferSize * sizeof(TCHAR)); if (!messageBuffer) { throwOutOfMemoryError(env, TEXT("TT2")); return; } /* Always set the count to -1 so we will loop again. */ count = -1; } } while (count < 0); /* We have the messageBuffer */ if ((jThrowableClass = (*env)->FindClass(env, throwableClassName)) != NULL) { if ((constructor = (*env)->GetMethodID(env, jThrowableClass, utf8MethodInit, utf8SigLjavaLangStringrV)) != NULL) { if ((jMessageBuffer = JNU_NewStringNative(env, messageBuffer)) != NULL) { if ((jThrowable = (*env)->NewObject(env, jThrowableClass, constructor, jMessageBuffer)) != NULL) { if ((*env)->Throw(env, jThrowable)) { _tprintf(TEXT("WrapperJNI Error: Unable to throw %s with message: %s"), throwableClassName, messageBuffer); fflush(NULL); } (*env)->DeleteLocalRef(env, jThrowable); } (*env)->DeleteLocalRef(env, jMessageBuffer); } } (*env)->DeleteLocalRef(env, jThrowableClass); } free(messageBuffer); } /** * Throws an OutOfMemoryError. * * @param env The current JNIEnv. * @param locationCode The locationCode to help tell where the error happened. */ void throwOutOfMemoryError(JNIEnv *env, const TCHAR* locationCode) { throwThrowable(env, (char*)utf8ClassJavaLangOutOfMemoryError, TEXT("Out of memory (%s)"), locationCode); _tprintf(TEXT("WrapperJNI Error: Out of memory (%s)\n"), locationCode); fflush(NULL); } void throwJNIError(JNIEnv *env, const TCHAR *message) { jclass exceptionClass; jmethodID constructor; jstring jMessage; jobject exception; if ((exceptionClass = (*env)->FindClass(env, utf8ClassOrgTanukisoftwareWrapperWrapperJNIError)) != NULL) { /* Look for the constructor. Ignore failures. */ if ((constructor = (*env)->GetMethodID(env, exceptionClass, utf8MethodInit, utf8Sig_BrV)) != NULL) { if ((jMessage = JNU_NewStringNative(env, message)) != NULL) { if ((exception = (*env)->NewObject(env, exceptionClass, constructor, jMessage)) != NULL) { if ((*env)->Throw(env, exception)) { _tprintf(TEXT("WrapperJNI Error: Unable to throw WrapperJNIError with message: %s"), message); fflush(NULL); } (*env)->DeleteLocalRef(env, exception); } (*env)->DeleteLocalRef(env, jMessage); } } (*env)->DeleteLocalRef(env, exceptionClass); } } void wrapperJNIHandleSignal(int signal) { if (wrapperLockControlEventQueue()) { /* Failed. Should have been reported. */ _tprintf(TEXT("WrapperJNI Error: Signal %d trapped, but ignored.\n"), signal); fflush(NULL); return; } #ifdef _DEBUG _tprintf(TEXT(" Queue Write 1 R:%d W:%d E:%d\n"), controlEventQueueLastReadIndex, controlEventQueueLastWriteIndex, signal); fflush(NULL); #endif controlEventQueueLastWriteIndex++; if (controlEventQueueLastWriteIndex >= CONTROL_EVENT_QUEUE_SIZE) { controlEventQueueLastWriteIndex = 0; } controlEventQueue[controlEventQueueLastWriteIndex] = signal; #ifdef _DEBUG _tprintf(TEXT(" Queue Write 2 R:%d W:%d\n"), controlEventQueueLastReadIndex, controlEventQueueLastWriteIndex); fflush(NULL); #endif if (wrapperReleaseControlEventQueue()) { /* Failed. Should have been reported. */ return; } } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetLibraryVersion * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetLibraryVersion(JNIEnv *env, jclass clazz) { jstring version; version = JNU_NewStringNative(env, wrapperVersion); return version; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeIsProfessionalEdition * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeIsProfessionalEdition(JNIEnv *env, jclass clazz) { return JNI_FALSE; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeIsStandardEdition * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeIsStandardEdition(JNIEnv *env, jclass clazz) { return JNI_FALSE; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetControlEvent * Signature: (V)I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetControlEvent(JNIEnv *env, jclass clazz) { int event = 0; if (wrapperLockControlEventQueue()) { /* Failed. Should have been reported. */ return 0; } if (controlEventQueueLastWriteIndex != controlEventQueueLastReadIndex) { #ifdef _DEBUG _tprintf(TEXT(" Queue Read 1 R:%d W:%d\n"), controlEventQueueLastReadIndex, controlEventQueueLastWriteIndex); fflush(NULL); #endif controlEventQueueLastReadIndex++; if (controlEventQueueLastReadIndex >= CONTROL_EVENT_QUEUE_SIZE) { controlEventQueueLastReadIndex = 0; } event = controlEventQueue[controlEventQueueLastReadIndex]; #ifdef _DEBUG _tprintf(TEXT(" Queue Read 2 R:%d W:%d E:%d\n"), controlEventQueueLastReadIndex, controlEventQueueLastWriteIndex, event); fflush(NULL); #endif } if (wrapperReleaseControlEventQueue()) { /* Failed. Should have been reported. */ return event; } return event; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: accessViolationInner * Signature: (V)V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_accessViolationInner(JNIEnv *env, jclass clazz) { TCHAR *ptr; /* Cause access violation */ ptr = NULL; ptr[0] = L'\n'; } JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeExec(JNIEnv *env, jclass jWrapperManagerClass, jobjectArray jCmdArray, jstring jCmdLine, jobject jWrapperProcessConfig, jboolean spawnChDir) { throwThrowable(env, "org/tanukisoftware/wrapper/WrapperLicenseError", TEXT("This function is only available in the Professional Edition of the Java Service Wrapper.")); return NULL; } wrapper_3.5.26_src/src/c/wrapperjni.h100644 0 0 10406 12440202301 14717 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ #ifndef _WRAPPERJNI_H #define _WRAPPERJNI_H #include "org_tanukisoftware_wrapper_WrapperManager.h" /*#define DEBUG_CHILD*/ #ifndef TRUE #define TRUE -1 #endif #undef gettext #ifdef WIN32 #include #endif #include #include "wrapper_i18n.h" #ifndef FALSE #define FALSE 0 #endif #ifdef WIN32 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 #endif #define strcmpIgnoreCase(str1, str2) _tcsicmp(str1, str2) /** Flag to keep track of whether StdOut has been redirected. */ extern int redirectedStdOut; /** Flag to keep track of whether StdErr has been redirected. */ extern int redirectedStdErr; extern void throwJNIError(JNIEnv *env, const TCHAR *message); /* Special symbols that need to be defined manually as part of the bootstrap process. */ extern const char utf8ClassJavaLangString[]; extern const char utf8MethodInit[]; extern const char utf8Sig_BrV[]; extern const char utf8Sigr_B[]; extern const char utf8MethodGetBytes[]; extern const char utf8ClassJavaLangOutOfMemoryError[]; /* Symbols which need to be defined. */ extern char *utf8SigLjavaLangStringrV; extern char *utf8ClassJavaLangSystem; extern char *utf8MethodGetProperties; extern char *utf8SigVrLjavaUtilProperties; extern char *utf8MethodGetProperty; extern char *utf8SigLjavaLangStringrLjavaLangString; extern char *utf8javaIOIOException; /* "java/io/IOException" */ #ifdef WIN32 #else /* UNIX specific symbols. */ extern char *utf8ClassOrgTanukisoftwareWrapperWrapperUNIXUser; extern char *utf8MethodSetGroup; extern char *utf8MethodAddGroup; extern char *utf8SigIIStringStringStringStringrV; extern char *utf8SigIStringrV; #endif #ifdef WIN32 #else extern jstring JNU_NewStringFromNativeChar(JNIEnv *env, const char *str); #endif extern int initCommon(); extern void throwOutOfMemoryError(JNIEnv *env, const TCHAR* locationCode); extern int wrapperSleep(int ms); extern int wrapperJNIDebugging; extern int wrapperLockControlEventQueue(); extern int wrapperReleaseControlEventQueue(); extern void wrapperJNIHandleSignal(int signal); extern void throwThrowable(JNIEnv *env, char *throwableClassName, const TCHAR *lpszFmt, ...); /** * Create a jstring from a Wide Char string. The jstring must be freed up by caller. * * @param env The current JNIEnv. * @param strW The Wide string to convert. * * @return The new jstring or NULL if there were any exceptions thrown. */ extern jstring JNU_NewStringNative(JNIEnv *env, const TCHAR *strW); extern TCHAR* JNU_GetStringNativeChars(JNIEnv *env, jstring jstr); extern void JNU_SetByteArrayRegion(JNIEnv *env, jbyteArray *jarray, jsize start, jsize len, const TCHAR *buffer); /** * Looks up a System property and sets its value in the propertyValue parameter. * * It is the responsibility of the caller to free up the propertyValue buffer if it is non-NULL. * * @param env Current JNIEnv. * @param propertyName Name of the property. * @param propertyValue Value of the property, or NULL if it was not set. * * @return TRUE if there were any problems, FALSE if successful. NULL values will still be successful. */ extern int getSystemProperty(JNIEnv *env, const TCHAR *propertyName, TCHAR **propertyValue, int encodeNative); #endif wrapper_3.5.26_src/src/c/wrapperjni_unix.c100644 0 0 37065 12440202301 15767 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ #ifndef WIN32 #include #include #include #include #include #include #include #include #include #include #include #include #include "loggerjni.h" #include "wrapperjni.h" static pid_t wrapperProcessId = -1; pthread_mutex_t controlEventQueueMutex = PTHREAD_MUTEX_INITIALIZER; int wrapperLockControlEventQueue() { int count = 0; /* Only wait for up to 30 seconds to make sure we don't get into a deadlock situation. * This could happen if a signal is encountered while locked. */ while (pthread_mutex_trylock(&controlEventQueueMutex) == EBUSY) { if (count >= 3000) { _tprintf(TEXT("WrapperJNI Error: Timed out waiting for control event queue lock.\n")); fflush(NULL); return -1; } wrapperSleep(10); count++; } if (count > 0) { if (wrapperJNIDebugging) { /* This is useful for making sure that the JNI call is working. */ _tprintf(TEXT("WrapperJNI Debug: wrapperLockControlEventQueue looped %d times before lock.\n"), count); fflush(NULL); } } return 0; } int wrapperReleaseControlEventQueue() { if (pthread_mutex_unlock(&controlEventQueueMutex)) { _tprintf(TEXT("WrapperJNI Error: Failed to unlock the event queue mutex.\n")); fflush(NULL); } return 0; } /** * Handle interrupt signals (i.e. Crtl-C). */ void handleInterrupt(int sig_num) { wrapperJNIHandleSignal(org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_C_EVENT); signal(SIGINT, handleInterrupt); } /** * Handle termination signals (i.e. machine is shutting down). */ void handleTermination(int sig_num) { wrapperJNIHandleSignal(org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_TERM_EVENT); signal(SIGTERM, handleTermination); } /** * Handle hangup signals. */ void handleHangup(int sig_num) { wrapperJNIHandleSignal(org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_HUP_EVENT); signal(SIGHUP, handleHangup); } /** * Handle usr1 signals. * * SIGUSR1 & SIGUSR2 are used by the JVM for internal garbage collection sweeps. * These signals MUST be passed on to the JVM or the JVM will hang. */ /* void handleUsr1(int sig_num) { wrapperJNIHandleSignal(org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_USR1_EVENT); signal(SIGUSR1, handleUsr1); } */ /** * Handle usr2 signals. * * SIGUSR1 & SIGUSR2 are used by the JVM for internal garbage collection sweeps. * These signals MUST be passed on to the JVM or the JVM will hang. */ /* void handleUsr2(int sig_num) { wrapperJNIHandleSignal(org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_USR2_EVENT); signal(SIGUSR2, handleUsr2); } */ /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeInit * Signature: (Z)V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeInit(JNIEnv *env, jclass jClassWrapperManager, jboolean debugging) { TCHAR *retLocale; wrapperJNIDebugging = debugging; /* Set the locale so we can display MultiByte characters. */ retLocale = _tsetlocale(LC_ALL, TEXT("")); #if defined(UNICODE) if (retLocale) { free(retLocale); } #endif if (wrapperJNIDebugging) { /* This is useful for making sure that the JNI call is working. */ _tprintf(TEXT("WrapperJNI Debug: Inside native WrapperManager initialization method\n")); fflush(NULL); } /* Set handlers for signals */ signal(SIGINT, handleInterrupt); signal(SIGTERM, handleTermination); signal(SIGHUP, handleHangup); /* signal(SIGUSR1, handleUsr1); signal(SIGUSR2, handleUsr2); */ if (initCommon(env, jClassWrapperManager)) { /* Failed. An exception will have been thrown. */ return; } /* Store the current process Id */ wrapperProcessId = getpid(); } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeRedirectPipes * Signature: ()I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeRedirectPipes(JNIEnv *evn, jclass clazz) { int fd; fd = _topen(TEXT("/dev/null"), O_RDWR, 0); if (fd != -1) { if (!redirectedStdErr) { _ftprintf(stderr, TEXT("WrapperJNI: Redirecting %s to /dev/null\n"), TEXT("StdErr")); fflush(NULL); if (dup2(fd, STDERR_FILENO) == -1) { _ftprintf(stderr, TEXT("WrapperJNI: Failed to redirect %s to /dev/null (Err: %s)\n"), TEXT("StdErr"), getLastErrorText()); fflush(NULL); } else { redirectedStdErr = TRUE; } } if (!redirectedStdOut) { _tprintf(TEXT("WrapperJNI: Redirecting %s to /dev/null\n"), TEXT("StdOut")); fflush(NULL); if (dup2(fd, STDOUT_FILENO) == -1) { _tprintf(TEXT("WrapperJNI: Failed to redirect %s to /dev/null (Err: %s)\n"), TEXT("StdOut"), getLastErrorText()); fflush(NULL); } else { redirectedStdOut = TRUE; } } } else { _ftprintf(stderr, TEXT("WrapperJNI: Failed to open /dev/null (Err: %s)\n"), getLastErrorText()); fflush(NULL); } return 0; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetJavaPID * Signature: ()I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetJavaPID(JNIEnv *env, jclass clazz) { return (int) getpid(); } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeRequestThreadGroup * Signature: ()V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeRequestThreadDump( JNIEnv *env, jclass clazz) { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: Sending SIGQUIT event to process group %d.\n"), (int)wrapperProcessId); fflush(NULL); } if (kill(wrapperProcessId, SIGQUIT) < 0) { _tprintf(TEXT("WrapperJNI Error: Unable to send SIGQUIT to JVM process: %s\n"), getLastErrorText()); fflush(NULL); } } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeSetConsoleTitle * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeSetConsoleTitle(JNIEnv *env, jclass clazz, jstring jstringTitle) { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: Setting the console title not supported on UNIX platforms.\n")); fflush(NULL); } } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetUser * Signature: (Z)Lorg/tanukisoftware/wrapper/WrapperUser; */ /*#define UVERBOSE*/ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetUser(JNIEnv *env, jclass clazz, jboolean groups) { jclass wrapperUserClass; jmethodID constructor; jmethodID setGroup; jmethodID addGroup; uid_t uid; struct passwd *pw; gid_t ugid; jstring jstringUser; jstring jstringRealName; jstring jstringHome; jstring jstringShell; jobject wrapperUser = NULL; struct group *aGroup; int member; int i; gid_t ggid; jstring jstringGroupName; /* Look for the WrapperUser class. Ignore failures as JNI throws an exception. */ if ((wrapperUserClass = (*env)->FindClass(env, utf8ClassOrgTanukisoftwareWrapperWrapperUNIXUser)) != NULL) { /* Look for the constructor. Ignore failures. */ if ((constructor = (*env)->GetMethodID(env, wrapperUserClass, utf8MethodInit, utf8SigIIStringStringStringStringrV)) != NULL) { uid = geteuid(); pw = getpwuid(uid); ugid = pw->pw_gid; /* Create the arguments to the constructor as java objects */ /* User */ jstringUser = JNU_NewStringFromNativeChar(env, pw->pw_name); if (jstringUser) { /* Real Name */ jstringRealName = JNU_NewStringFromNativeChar(env, pw->pw_gecos); if (jstringRealName) { /* Home */ jstringHome = JNU_NewStringFromNativeChar(env, pw->pw_dir); if (jstringHome) { /* Shell */ jstringShell = JNU_NewStringFromNativeChar(env, pw->pw_shell); if (jstringShell) { /* Now create the new wrapperUser using the constructor arguments collected above. */ wrapperUser = (*env)->NewObject(env, wrapperUserClass, constructor, uid, ugid, jstringUser, jstringRealName, jstringHome, jstringShell); /* If the caller requested the user's groups then look them up. */ if (groups) { /* Set the user group. */ if ((setGroup = (*env)->GetMethodID(env, wrapperUserClass, utf8MethodSetGroup, utf8SigIStringrV)) != NULL) { if ((aGroup = getgrgid(ugid)) != NULL) { ggid = aGroup->gr_gid; /* Group name */ jstringGroupName = JNU_NewStringFromNativeChar(env, aGroup->gr_name); if (jstringGroupName) { /* Add the group to the user. */ (*env)->CallVoidMethod(env, wrapperUser, setGroup, ggid, jstringGroupName); (*env)->DeleteLocalRef(env, jstringGroupName); } else { /* Exception Thrown */ } } } else { /* Exception Thrown */ } /* Look for the addGroup method. Ignore failures. */ if ((addGroup = (*env)->GetMethodID(env, wrapperUserClass, utf8MethodAddGroup, utf8SigIStringrV)) != NULL) { setgrent(); while ((aGroup = getgrent()) != NULL) { /* Search the member list to decide whether or not the user is a member. */ member = 0; i = 0; while ((member == 0) && aGroup->gr_mem[i]) { if (strcmp(aGroup->gr_mem[i], pw->pw_name) == 0) { member = 1; } i++; } if (member) { ggid = aGroup->gr_gid; /* Group name */ jstringGroupName = JNU_NewStringFromNativeChar(env, aGroup->gr_name); if (jstringGroupName) { /* Add the group to the user. */ (*env)->CallVoidMethod(env, wrapperUser, addGroup, ggid, jstringGroupName); (*env)->DeleteLocalRef(env, jstringGroupName); } else { /* Exception Thrown */ } } } endgrent(); } else { /* Exception Thrown */ } } (*env)->DeleteLocalRef(env, jstringShell); } else { /* Exception Thrown */ } (*env)->DeleteLocalRef(env, jstringHome); } else { /* Exception Thrown */ } (*env)->DeleteLocalRef(env, jstringRealName); } else { /* Exception Thrown */ } (*env)->DeleteLocalRef(env, jstringUser); } else { /* Exception Thrown */ } } else { /* Exception Thrown */ } (*env)->DeleteLocalRef(env, wrapperUserClass); } return wrapperUser; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetInteractiveUser * Signature: (Z)Lorg/tanukisoftware/wrapper/WrapperUser; */ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetInteractiveUser(JNIEnv *env, jclass clazz, jboolean groups) { /* If the DISPLAY environment variable is set then assume that this user * has access to an X display, in which case we will return the same thing * as nativeGetUser. */ if (getenv("DISPLAY")) { /* This is an interactive JVM since it has access to a display. */ return Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetUser(env, clazz, groups); } else { /* There is no DISPLAY variable, so assume that this JVM is non-interactive. */ return NULL; } } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeListServices * Signature: ()[Lorg/tanukisoftware/wrapper/WrapperWin32Service; */ JNIEXPORT jobjectArray JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeListServices(JNIEnv *env, jclass clazz) { /** Not supported on UNIX platforms. */ return NULL; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeSendServiceControlCode * Signature: (Ljava/lang/String;I)Lorg/tanukisoftware/wrapper/WrapperWin32Service; */ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeSendServiceControlCode(JNIEnv *env, jclass clazz, jbyteArray serviceName, jint controlCode) { /** Not supported on UNIX platforms. */ return NULL; } #endif wrapper_3.5.26_src/src/c/wrapperjni_win.c100644 0 0 145513 12440202301 15617 0ustar 0 0 /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ #ifndef WIN32 /* For some reason this is not defined sometimes when I build on MFVC 6.0 $%$%$@@!! * This causes a compiler error to let me know about the problem. Anyone with any * ideas as to why this sometimes happens or how to fix it, please let me know. */ barf #endif #ifdef WIN32 #include #include #include #include #include #include #include "loggerjni.h" #include "wrapperjni.h" /* The largest possible command line length on Windows. */ #define MAX_COMMAND_LINE_LEN 32766 /* MS Visual Studio 8 went and deprecated the POXIX names for functions. * Fixing them all would be a big headache for UNIX versions. */ #pragma warning(disable : 4996) /* Reference to HINSTANCE of this DLL */ EXTERN_C IMAGE_DOS_HEADER __ImageBase; static DWORD javaProcessId = 0; HANDLE controlEventQueueMutexHandle = NULL; FARPROC OptionalProcess32First = NULL; FARPROC OptionalProcess32Next = NULL; FARPROC OptionalThread32First = NULL; FARPROC OptionalThread32Next = NULL; FARPROC OptionalCreateToolhelp32Snapshot = NULL; int wrapperLockControlEventQueue() { #ifdef _DEBUG _tprintf(TEXT(" wrapperLockControlEventQueue()\n")); fflush(NULL); #endif if (!controlEventQueueMutexHandle) { /* Not initialized so fail quietly. A message was shown on startup. */ return -1; } /* Only wait for up to 30 seconds to make sure we don't get into a deadlock situation. * This could happen if a signal is encountered while locked. */ switch (WaitForSingleObject(controlEventQueueMutexHandle, 30000)) { case WAIT_ABANDONED: _tprintf(TEXT("WrapperJNI Error: Control Event mutex was abandoned.\n")); fflush(NULL); return -1; case WAIT_FAILED: _tprintf(TEXT("WrapperJNI Error: Control Event mutex wait failed.\n")); fflush(NULL); return -1; case WAIT_TIMEOUT: _tprintf(TEXT("WrapperJNI Error: Control Event mutex wait timed out.\n")); fflush(NULL); return -1; default: /* Ok */ break; } return 0; } int wrapperReleaseControlEventQueue() { #ifdef _DEBUG _tprintf(TEXT(" wrapperReleaseControlEventQueue()\n")); fflush(NULL); #endif if (!ReleaseMutex(controlEventQueueMutexHandle)) { _tprintf(TEXT( "WrapperJNI Error: Failed to release Control Event mutex. %s\n"), getLastErrorText()); fflush(NULL); return -1; } return 0; } /** * Handler to take care of the case where the user hits CTRL-C when the wrapper * is being run as a console. If this is not done, then the Java process * would exit due to a CTRL_LOGOFF_EVENT when a user logs off even if the * application is installed as a service. * * Handlers are called in the reverse order that they are registered until one * returns TRUE. So last registered is called first until the default handler * is called. This means that if we return FALSE, the JVM'S handler will then * be called. */ int wrapperConsoleHandler(int key) { int event; /* Call the control callback in the java code */ switch(key) { case CTRL_C_EVENT: event = org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_C_EVENT; break; case CTRL_BREAK_EVENT: /* This is a request to do a thread dump. Let the JVM handle this. */ return FALSE; case CTRL_CLOSE_EVENT: event = org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_CLOSE_EVENT; break; case CTRL_LOGOFF_EVENT: event = org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_LOGOFF_EVENT; break; case CTRL_SHUTDOWN_EVENT: event = org_tanukisoftware_wrapper_WrapperManager_WRAPPER_CTRL_SHUTDOWN_EVENT; break; default: event = key; } if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: Got Control Signal %d->%d\n"), key, event); flushall(); } wrapperJNIHandleSignal(event); if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: Handled signal\n")); flushall(); } return TRUE; /* We handled the event. */ } /** * Looks up the name of the explorer.exe file in the registry. It may change * in a future version of windows, so this is the safe thing to do. */ TCHAR explorerExe[1024]; void initExplorerExeName() { /* Location: "\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell" */ _sntprintf(explorerExe, 1024, TEXT("Explorer.exe")); } void throwException(JNIEnv *env, const char *className, int jErrorCode, const TCHAR *message) { jclass exceptionClass; jmethodID constructor; jbyteArray jMessage; jobject exception; if (exceptionClass = (*env)->FindClass(env, className)) { /* Look for the constructor. Ignore failures. */ if (constructor = (*env)->GetMethodID(env, exceptionClass, "", "(I[B)V")) { jMessage = (*env)->NewByteArray(env, (jsize)_tcslen(message) * sizeof(TCHAR)); /* The 1.3.1 jni.h file does not specify the message as const. The cast is to * avoid compiler warnings trying to pass a (const TCHAR *) as a (TCHAR *). */ JNU_SetByteArrayRegion(env, &jMessage, 0, (jsize)_tcslen(message) * sizeof(TCHAR), message); exception = (*env)->NewObject(env, exceptionClass, constructor, jErrorCode, jMessage); if ((*env)->Throw(env, exception)) { _tprintf(TEXT("WrapperJNI Error: Unable to throw exception of class '%s' with message: %s"), className, message); flushall(); } (*env)->DeleteLocalRef(env, jMessage); (*env)->DeleteLocalRef(env, exception); } (*env)->DeleteLocalRef(env, exceptionClass); } else { _tprintf(TEXT("WrapperJNI Error: Unable to load class, '%s' to report exception: %s"), className, message); flushall(); } } void throwServiceException(JNIEnv *env, int errorCode, const TCHAR *message) { throwException(env, "org/tanukisoftware/wrapper/WrapperServiceException", errorCode, message); } /** * Converts a FILETIME to a time_t structure. */ time_t fileTimeToTimeT(FILETIME *filetime) { SYSTEMTIME utc; SYSTEMTIME local; TIME_ZONE_INFORMATION timeZoneInfo; struct tm tm; FileTimeToSystemTime(filetime, &utc); GetTimeZoneInformation(&timeZoneInfo); SystemTimeToTzSpecificLocalTime(&timeZoneInfo, &utc, &local); tm.tm_sec = local.wSecond; tm.tm_min = local.wMinute; tm.tm_hour = local.wHour; tm.tm_mday = local.wDay; tm.tm_mon = local.wMonth - 1; tm.tm_year = local.wYear - 1900; tm.tm_wday = local.wDayOfWeek; tm.tm_yday = -1; tm.tm_isdst = -1; return mktime(&tm); } /** * Looks for the login time given a user SID. The login time is found by looking * up the SID in the registry. */ time_t getUserLoginTime(TCHAR *sidText) { LONG result; LPSTR pBuffer = NULL; HKEY userKey; int i; TCHAR userKeyName[MAX_PATH]; DWORD userKeyNameSize; FILETIME lastTime; time_t loginTime; loginTime = 0; /* Open a key to the HKRY_USERS registry. */ result = RegOpenKey(HKEY_USERS, NULL, &userKey); if (result != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); _tprintf(TEXT("WrapperJNI Error: Error opening registry for HKEY_USERS: %s\n"), getLastErrorText()); flushall(); LocalFree(pBuffer); return loginTime; } /* Loop over the users */ i = 0; userKeyNameSize = sizeof(userKeyName); while ((result = RegEnumKeyEx(userKey, i, userKeyName, &userKeyNameSize, NULL, NULL, NULL, &lastTime)) == ERROR_SUCCESS) { if (_tcsicmp(sidText, userKeyName) == 0) { /* We found the SID! */ /* Convert the FILETIME to UNIX time. */ loginTime = fileTimeToTimeT(&lastTime); break; } userKeyNameSize = sizeof(userKeyName); i++; } if (result != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); printf("WrapperJNI Error: Unable to enumerate the registry: %d : %s", result, pBuffer); flushall(); LocalFree(pBuffer); } /* Always close the userKey. */ result = RegCloseKey(userKey); if (result != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, result, 0, (LPTSTR)&pBuffer, 0, NULL); printf("WrapperJNI Error: Unable to close the registry: %d : %s", result, pBuffer); flushall(); LocalFree(pBuffer); } return loginTime; } /** * Sets group information in a user object. * * Returns TRUE if there were any problems. */ int setUserGroups(JNIEnv *env, jclass wrapperUserClass, jobject wrapperUser, HANDLE hProcessToken) { jmethodID addGroup; TOKEN_GROUPS *tokenGroups; DWORD tokenGroupsSize; DWORD i; TCHAR *sidText; TCHAR *groupName; DWORD groupNameSize; TCHAR *domainName; DWORD domainNameSize; SID_NAME_USE sidType; jstring jstringSID; jstring jstringGroupName; jstring jstringDomainName; int result = FALSE; /* Look for the method used to add groups to the user. */ if (addGroup = (*env)->GetMethodID(env, wrapperUserClass, "addGroup", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")) { /* Get the TokenGroups info from the token. */ GetTokenInformation(hProcessToken, TokenGroups, NULL, 0, &tokenGroupsSize); tokenGroups = (TOKEN_GROUPS *)malloc(tokenGroupsSize); if (!tokenGroups) { throwOutOfMemoryError(env, TEXT("SUG1")); result = TRUE; } else { if (GetTokenInformation(hProcessToken, TokenGroups, tokenGroups, tokenGroupsSize, &tokenGroupsSize)) { /* Loop over each of the groups and add each one to the user. */ for (i = 0; i < tokenGroups->GroupCount; i++) { /* Get the text representation of the sid. */ if (ConvertSidToStringSid(tokenGroups->Groups[i].Sid, &sidText) == 0) { _tprintf(TEXT("WrapperJNI Error: Failed to Convert SId to String: %s\n"), getLastErrorText()); result = TRUE; } else { /* We now have an SID, use it to lookup the account. */ groupNameSize = 0; domainNameSize = 0; LookupAccountSid(NULL, tokenGroups->Groups[i].Sid, NULL, &groupNameSize, NULL, &domainNameSize, &sidType); groupName = (TCHAR*)malloc(sizeof(TCHAR) * groupNameSize); if (!groupName) { throwOutOfMemoryError(env, TEXT("SUG3")); result = TRUE; } else { domainName = (TCHAR*)malloc(sizeof(TCHAR) * domainNameSize); if (!domainName) { throwOutOfMemoryError(env, TEXT("SUG4")); result = TRUE; } else { if (LookupAccountSid(NULL, tokenGroups->Groups[i].Sid, groupName, &groupNameSize, domainName, &domainNameSize, &sidType)) { /* Create the arguments to the constructor as java objects */ /* SID byte array */ jstringSID = JNU_NewStringNative(env, sidText); if (jstringSID) { /* GroupName byte array */ jstringGroupName = JNU_NewStringNative(env, groupName); if (jstringGroupName) { /* DomainName byte array */ jstringDomainName = JNU_NewStringNative(env, domainName); if (jstringDomainName) { /* Now actually add the group to the user. */ (*env)->CallVoidMethod(env, wrapperUser, addGroup, jstringSID, jstringGroupName, jstringDomainName); (*env)->DeleteLocalRef(env, jstringDomainName); } else { /* Exception Thrown */ break; } (*env)->DeleteLocalRef(env, jstringGroupName); } else { /* Exception Thrown */ break; } (*env)->DeleteLocalRef(env, jstringSID); } else { /* Exception Thrown */ break; } } else { /* This is normal as some accounts do not seem to be mappable. */ /* _tprintf(TEXT("WrapperJNI Debug: Unable to locate account for Sid, %s: %s\n"), sidText, getLastErrorText()); flushall(); */ } free(domainName); } free(groupName); } LocalFree(sidText); } } } else { _tprintf(TEXT("WrapperJNI Error: Unable to get token information: %s\n"), getLastErrorText()); flushall(); } free(tokenGroups); } } else { /* Exception Thrown */ } return result; } /** * Creates and returns a WrapperUser instance to represent the user who owns * the specified process Id. */ jobject createWrapperUserForProcess(JNIEnv *env, DWORD processId, jboolean groups) { HANDLE hProcess; HANDLE hProcessToken; TOKEN_USER *tokenUser; DWORD tokenUserSize; TCHAR *sidText; TCHAR *userName; DWORD userNameSize; TCHAR *domainName; DWORD domainNameSize; SID_NAME_USE sidType; time_t loginTime; jclass wrapperUserClass; jmethodID constructor; jstring jstringSID; jstring jstringUserName; jstring jstringDomainName; jobject wrapperUser = NULL; if (hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processId)) { if (OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken)) { GetTokenInformation(hProcessToken, TokenUser, NULL, 0, &tokenUserSize); tokenUser = (TOKEN_USER *)malloc(tokenUserSize); if (!tokenUser) { throwOutOfMemoryError(env, TEXT("CWUFP1")); } else { if (GetTokenInformation(hProcessToken, TokenUser, tokenUser, tokenUserSize, &tokenUserSize)) { /* Get the text representation of the sid. */ if (ConvertSidToStringSid(tokenUser->User.Sid, &sidText) == 0) { _tprintf(TEXT("Failed to Convert SId to String: %s\n"), getLastErrorText()); } else { /* We now have an SID, use it to lookup the account. */ userNameSize = 0; domainNameSize = 0; LookupAccountSid(NULL, tokenUser->User.Sid, NULL, &userNameSize, NULL, &domainNameSize, &sidType); userName = (TCHAR*)malloc(sizeof(TCHAR) * userNameSize); if (!userName) { throwOutOfMemoryError(env, TEXT("CWUFP3")); } else { domainName = (TCHAR*)malloc(sizeof(TCHAR) * domainNameSize); if (!domainName) { throwOutOfMemoryError(env, TEXT("CWUFP4")); } else { if (LookupAccountSid(NULL, tokenUser->User.Sid, userName, &userNameSize, domainName, &domainNameSize, &sidType)) { /* Get the time that this user logged in. */ loginTime = getUserLoginTime(sidText); /* Look for the WrapperUser class. Ignore failures as JNI throws an exception. */ if (wrapperUserClass = (*env)->FindClass(env, "org/tanukisoftware/wrapper/WrapperWin32User")) { /* Look for the constructor. Ignore failures. */ if (constructor = (*env)->GetMethodID(env, wrapperUserClass, "", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V")) { /* Create the arguments to the constructor as java objects */ /* SID */ jstringSID = JNU_NewStringNative(env, sidText); if (jstringSID) { /* UserName */ jstringUserName = JNU_NewStringNative(env, userName); if (jstringUserName) { /* DomainName */ jstringDomainName = JNU_NewStringNative(env, domainName); if (jstringDomainName) { /* Now create the new wrapperUser using the constructor arguments collected above. */ wrapperUser = (*env)->NewObject(env, wrapperUserClass, constructor, jstringSID, jstringUserName, jstringDomainName, loginTime); /* If the caller requested the user's groups then look them up. */ if (groups) { if (setUserGroups(env, wrapperUserClass, wrapperUser, hProcessToken)) { /* Failed. Just continue without groups. */ } } (*env)->DeleteLocalRef(env, jstringDomainName); } else { /* Exception Thrown */ } (*env)->DeleteLocalRef(env, jstringUserName); } else { /* Exception Thrown */ } (*env)->DeleteLocalRef(env, jstringSID); } else { /* Exception Thrown */ } } else { /* Exception Thrown */ } (*env)->DeleteLocalRef(env, wrapperUserClass); } else { /* Exception Thrown */ } } else { /* This is normal as some accounts do not seem to be mappable. */ /* printf(TEXT("WrapperJNI Debug: Unable to locate account for Sid, %s: %s\n"), sidText, getLastErrorText()); flushall(); */ } free(domainName); } free(userName); } LocalFree(sidText); } } else { _tprintf(TEXT("WrapperJNI Error: Unable to get token information: %s\n"), getLastErrorText()); flushall(); } free(tokenUser); } CloseHandle(hProcessToken); } else { _tprintf(TEXT("WrapperJNI Error: Unable to open process token: %s\n"), getLastErrorText()); flushall(); } CloseHandle(hProcess); } else { _tprintf(TEXT("WrapperJNI Error: Unable to open process: %s\n"), getLastErrorText()); flushall(); } return wrapperUser; } HMODULE kernel32Mod; void loadDLLProcs() { if ((kernel32Mod = GetModuleHandle(TEXT("KERNEL32.DLL"))) == NULL) { _tprintf(TEXT("WrapperJNI Error: Unable to load KERNEL32.DLL: %s\n"), getLastErrorText()); flushall(); return; } #ifdef UNICODE if ((OptionalProcess32First = GetProcAddress(kernel32Mod, "Process32FirstW")) == NULL) { #else if ((OptionalProcess32First = GetProcAddress(kernel32Mod, "Process32First")) == NULL) { #endif if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: The Process32First function is not available on this version of Windows.\n")); flushall(); } } #ifdef UNICODE if ((OptionalProcess32Next = GetProcAddress(kernel32Mod, "Process32NextW")) == NULL) { #else if ((OptionalProcess32Next = GetProcAddress(kernel32Mod, "Process32Next")) == NULL) { #endif if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: The Process32Next function is not available on this version of Windows.\n")); flushall(); } } if ((OptionalThread32First = GetProcAddress(kernel32Mod, "Thread32First")) == NULL) { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: The Thread32First function is not available on this version of Windows.\n")); flushall(); } } if ((OptionalThread32Next = GetProcAddress(kernel32Mod, "Thread32Next")) == NULL) { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: The Thread32Next function is not available on this version of Windows.\n")); flushall(); } } if ((OptionalCreateToolhelp32Snapshot = GetProcAddress(kernel32Mod, "CreateToolhelp32Snapshot")) == NULL) { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: The CreateToolhelp32Snapshot function is not available on this version of Windows.\n")); flushall(); } } } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeInit * Signature: (Z)V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeInit(JNIEnv *env, jclass jClassWrapperManager, jboolean debugging) { TCHAR szPath[_MAX_PATH]; DWORD usedLen; OSVERSIONINFO osVer; wrapperJNIDebugging = debugging; /* Set the locale so we can display MultiByte characters. */ _tsetlocale(LC_ALL, TEXT("")); if (wrapperJNIDebugging) { /* This is useful for making sure that the JNI call is working. */ _tprintf(TEXT("WrapperJNI Debug: Initializing WrapperManager native library.\n")); flushall(); usedLen = GetModuleFileName(NULL, szPath, _MAX_PATH); if (usedLen == 0) { _tprintf(TEXT("WrapperJNI Debug: Unable to retrieve the Java process file name. %s\n"), getLastErrorText()); flushall(); } else if ((usedLen == _MAX_PATH) || (getLastError() == ERROR_INSUFFICIENT_BUFFER)) { _tprintf(TEXT("WrapperJNI Debug: Unable to retrieve the Java process file name. %s\n"), TEXT("Path too long.")); flushall(); } else { _tprintf(TEXT("WrapperJNI Debug: Java Executable: %s\n"), szPath); flushall(); } usedLen = GetModuleFileName((HINSTANCE)&__ImageBase, szPath, _MAX_PATH); if (usedLen == 0) { _tprintf(TEXT("WrapperJNI Debug: Unable to retrieve the native library file name. %s\n"), getLastErrorText()); flushall(); } else if ((usedLen == _MAX_PATH) || (getLastError() == ERROR_INSUFFICIENT_BUFFER)) { _tprintf(TEXT("WrapperJNI Debug: Unable to retrieve the native library file name. %s\n"), TEXT("Path too long.")); flushall(); } else { _tprintf(TEXT("WrapperJNI Debug: Native Library: %s\n"), szPath); flushall(); } } if (initCommon(env, jClassWrapperManager)) { /* Failed. An exception will have been thrown. */ return; } osVer.dwOSVersionInfoSize = sizeof(osVer); if (GetVersionEx(&osVer)) { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: Windows version: %ld.%ld.%ld\n"), osVer.dwMajorVersion, osVer.dwMinorVersion, osVer.dwBuildNumber); flushall(); } } else { _tprintf(TEXT("WrapperJNI Error: Unable to retrieve the Windows version information.\n")); flushall(); } loadDLLProcs(); if (!(controlEventQueueMutexHandle = CreateMutex(NULL, FALSE, NULL))) { _tprintf(TEXT("WrapperJNI Error: Failed to create control event queue mutex. Signals will be ignored. %s\n"), getLastErrorText()); flushall(); controlEventQueueMutexHandle = NULL; } /* Make sure that the handling of CTRL-C signals is enabled for this process. */ if (!SetConsoleCtrlHandler(NULL, FALSE)) { _tprintf(TEXT("WrapperJNI Error: Attempt to reset control signal handlers failed. %s\n"), getLastErrorText()); flushall(); } /* Initialize the CTRL-C handler */ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)wrapperConsoleHandler, TRUE)) { _tprintf(TEXT("WrapperJNI Error: Attempt to register a control signal handler failed. %s\n"), getLastErrorText()); flushall(); } /* Store the current process Id */ javaProcessId = GetCurrentProcessId(); /* Initialize the explorer.exe name. */ initExplorerExeName(); } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeRedirectPipes * Signature: ()I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeRedirectPipes(JNIEnv *evn, jclass clazz) { /* We don't need to do anything on Windows. */ return 0; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetJavaPID * Signature: ()I */ JNIEXPORT jint JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetJavaPID(JNIEnv *env, jclass clazz) { return GetCurrentProcessId(); } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeRequestThreadDump * Signature: ()V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeRequestThreadDump(JNIEnv *env, jclass clazz) { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: Sending BREAK event to process group %ld.\n"), javaProcessId); flushall(); } if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, javaProcessId) == 0) { if (getLastError() == 6) { _tprintf(TEXT("WrapperJNI Error: Unable to send BREAK event to JVM process because it does not have a console.\n")); flushall(); } else { _tprintf(TEXT("WrapperJNI Error: Unable to send BREAK event to JVM process: %s\n"), getLastErrorText()); flushall(); } } } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeSetConsoleTitle * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeSetConsoleTitle(JNIEnv *env, jclass clazz, jstring jstringTitle) { TCHAR *title; title = JNU_GetStringNativeChars(env, jstringTitle); if (!title) { throwOutOfMemoryError(env, TEXT("NSCT1")); } else { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: Setting the console title to: %s\n"), title); flushall(); } SetConsoleTitle(title); free(title); } } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetUser * Signature: (Z)Lorg/tanukisoftware/wrapper/WrapperUser; */ /*#define UVERBOSE*/ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetUser(JNIEnv *env, jclass clazz, jboolean groups) { DWORD processId; #ifdef UVERBOSE _tprintf(TEXT("WrapperJNI Debug: nativeGetUser()\n")); flushall(); #endif /* Get the current processId. */ processId = GetCurrentProcessId(); return createWrapperUserForProcess(env, processId, groups); } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeGetInteractiveUser * Signature: (Z)Lorg/tanukisoftware/wrapper/WrapperUser; */ /*#define IUVERBOSE*/ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetInteractiveUser(JNIEnv *env, jclass clazz, jboolean groups) { HANDLE snapshot; PROCESSENTRY32 processEntry; THREADENTRY32 threadEntry; BOOL foundThread; HDESK desktop; jobject wrapperUser = NULL; #ifdef IUVERBOSE _tprintf(TEXT("WrapperJNI Debug: nativeGetInteractiveUser()\n")); flushall(); #endif /* This function will only work if all required optional functions existed. */ if ((OptionalProcess32First == NULL) || (OptionalProcess32Next == NULL) || (OptionalThread32First == NULL) || (OptionalThread32Next == NULL) || (OptionalCreateToolhelp32Snapshot == NULL)) { if (wrapperJNIDebugging) { _tprintf(TEXT("WrapperJNI Debug: getInteractiveUser not supported on this platform.\n")); flushall(); } return NULL; } /* In order to be able to return the interactive user, we first need to locate the * logged on user whose desktop we are able to open. On XP systems, there will be * more than one user with a desktop, but only the first one to log on will allow * us to open its desktop. On all NT systems, there will be additional logged on * users if there are other services running. */ if ((snapshot = (HANDLE)OptionalCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0)) >= 0) { processEntry.dwSize = sizeof(processEntry); if (OptionalProcess32First(snapshot, &processEntry)) { do { /* We are only interrested in the Explorer processes. */ if (_tcsicmp(explorerExe, processEntry.szExeFile) == 0) { #ifdef IUVERBOSE _tprintf(TEXT("WrapperJNI Debug: Process size=%ld, cnt=%ld, id=%ld, parentId=%ld, moduleId=%ld, threads=%ld, exe=%s\n"), processEntry.dwSize, processEntry.cntUsage, processEntry.th32ProcessID, processEntry.th32ParentProcessID, processEntry.th32ModuleID, processEntry.cntThreads, processEntry.szExeFile); flushall(); #endif /* Now look for a thread which is owned by the explorer process. */ threadEntry.dwSize = sizeof(threadEntry); if (OptionalThread32First(snapshot, &threadEntry)) { foundThread = FALSE; do { /* We are only interrested in threads that belong to the current Explorer process. */ if (threadEntry.th32OwnerProcessID == processEntry.th32ProcessID) { #ifdef IUVERBOSE _tprintf(TEXT("WrapperJNI Debug: Thread Id=%ld\n"), threadEntry.th32ThreadID); flushall(); #endif /* We have a thread, now see if we can gain access to its desktop */ if (desktop = GetThreadDesktop(threadEntry.th32ThreadID)) { /* We got the desktop! We now know that this is the thread and thus * process that we have been looking for. Unfortunately it does not * appear that we can get the Sid of the account directly from this * desktop. I tried using GetUserObjectInformation, but the Sid * returned does not seem to map to a valid account. */ wrapperUser = createWrapperUserForProcess(env, processEntry.th32ProcessID, groups); } else { #ifdef IUVERBOSE _tprintf(TEXT("WrapperJNI Debug: GetThreadDesktop failed: %s\n"), getLastErrorText()); flushall(); #endif } /* We only need the first thread, so break */ foundThread = TRUE; break; } } while (OptionalThread32Next(snapshot, &threadEntry)); if (!foundThread && (GetLastError() != ERROR_NO_MORE_FILES)) { #ifdef IUVERBOSE _tprintf(TEXT("WrapperJNI Debug: Unable to get next thread entry: %s\n"), getLastErrorText()); flushall(); #endif } } else if (GetLastError() != ERROR_NO_MORE_FILES) { _tprintf(TEXT("WrapperJNI Debug: Unable to get first thread entry: %s\n"), getLastErrorText()); flushall(); } } } while (OptionalProcess32Next(snapshot, &processEntry)); #ifdef IUVERBOSE if (GetLastError() != ERROR_NO_MORE_FILES) { _tprintf(TEXT("WrapperJNI Debug: Unable to get next process entry: %s\n"), getLastErrorText()); flushall(); } #endif } else if (GetLastError() != ERROR_NO_MORE_FILES) { _tprintf(TEXT("WrapperJNI Error: Unable to get first process entry: %s\n"), getLastErrorText()); flushall(); } CloseHandle(snapshot); } else { _tprintf(TEXT("WrapperJNI Error: Toolhelp snapshot failed: %s\n"), getLastErrorText()); flushall(); } return wrapperUser; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeListServices * Signature: ()[Lorg/tanukisoftware/wrapper/WrapperWin32Service; */ JNIEXPORT jobjectArray JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeListServices(JNIEnv *env, jclass clazz) { TCHAR buffer[512]; SC_HANDLE hSCManager; DWORD size, sizeNeeded, servicesReturned, resumeHandle; DWORD err; ENUM_SERVICE_STATUS *services = NULL; BOOL threwError = FALSE; DWORD i; jobjectArray serviceArray = NULL; jclass serviceClass; jmethodID constructor; jstring jStringName; jstring jStringDisplayName; DWORD state; DWORD exitCode; jobject service; hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); if (hSCManager) { /* Before we can get the list of services, we need to know how much memory it will take. */ resumeHandle = 0; if (!EnumServicesStatus(hSCManager, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &sizeNeeded, &servicesReturned, &resumeHandle)) { err = GetLastError(); if ((err == ERROR_MORE_DATA) || (err == ERROR_INSUFFICIENT_BUFFER)) { /* Allocate the needed memory and call again. */ size = sizeNeeded; services = malloc(size); if (!services) { throwOutOfMemoryError(env, TEXT("NLS1")); } else { if (!EnumServicesStatus(hSCManager, SERVICE_WIN32, SERVICE_STATE_ALL, services, size, &sizeNeeded, &servicesReturned, &resumeHandle)) { /* Failed to get the services. */ _sntprintf(buffer, 512, TEXT("Unable to enumerate the system services: %s"), getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } else { /* Success. */ } /* free(services) is done below. */ } } else { _sntprintf(buffer, 512, TEXT("Unable to enumerate the system services: %s"), getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } } else { /* Success which means that no services were found. */ } if (!threwError) { if (serviceClass = (*env)->FindClass(env, "org/tanukisoftware/wrapper/WrapperWin32Service")) { /* Look for the constructor. Ignore failures. */ if (constructor = (*env)->GetMethodID(env, serviceClass, "", "(Ljava/lang/String;Ljava/lang/String;II)V")) { serviceArray = (*env)->NewObjectArray(env, servicesReturned, serviceClass, NULL); for (i = 0; i < servicesReturned; i++) { jStringName = JNU_NewStringNative(env, services[i].lpServiceName); if (jStringName) { jStringDisplayName = JNU_NewStringNative(env, services[i].lpDisplayName); if (jStringDisplayName) { state = services[i].ServiceStatus.dwCurrentState; exitCode = services[i].ServiceStatus.dwWin32ExitCode; if (exitCode == ERROR_SERVICE_SPECIFIC_ERROR) { exitCode = services[i].ServiceStatus.dwServiceSpecificExitCode; } service = (*env)->NewObject(env, serviceClass, constructor, jStringName, jStringDisplayName, state, exitCode); (*env)->SetObjectArrayElement(env, serviceArray, i, service); (*env)->DeleteLocalRef(env, service); (*env)->DeleteLocalRef(env, jStringDisplayName); } else { /* Exception Thrown */ break; } (*env)->DeleteLocalRef(env, jStringName); } else { /* Exception Thrown */ break; } } } (*env)->DeleteLocalRef(env, serviceClass); } else { /* Unable to load the service class. */ _sntprintf(buffer, 512, TEXT("Unable to locate class org.tanukisoftware.wrapper.WrapperWin32Service")); throwServiceException(env, 1, buffer); } } if (services != NULL) { free(services); } /* Close the handle to the service control manager database */ CloseServiceHandle(hSCManager); } else { /* Unable to open the service manager. */ _sntprintf(buffer, 512, TEXT("Unable to open the Windows service control manager database: %s"), getLastErrorText()); throwServiceException(env, GetLastError(), buffer); } return serviceArray; } /* * Class: org_tanukisoftware_wrapper_WrapperManager * Method: nativeSendServiceControlCode * Signature: (Ljava/lang/String;I)Lorg/tanukisoftware/wrapper/WrapperWin32Service; */ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeSendServiceControlCode(JNIEnv *env, jclass clazz, jstring jStringServiceName, jint controlCode) { jobject service = NULL; TCHAR *serviceName; size_t bufferSize = 2048; TCHAR buffer[2048]; SC_HANDLE hSCManager; SC_HANDLE hService; int serviceAccess; DWORD wControlCode; BOOL threwError = FALSE; SERVICE_STATUS serviceStatus; jclass serviceClass; jmethodID constructor; DWORD displayNameSize; TCHAR *displayName; jstring jStringDisplayName; DWORD state; DWORD exitCode; if ((serviceName = JNU_GetStringNativeChars(env, jStringServiceName))) { hSCManager = OpenSCManager(NULL, NULL, GENERIC_READ); if (hSCManager) { /* Decide on the access needed when opening the service. */ if (controlCode == org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_START) { serviceAccess = SERVICE_START | SERVICE_INTERROGATE | SERVICE_QUERY_STATUS; wControlCode = SERVICE_CONTROL_INTERROGATE; } else if (controlCode == org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_STOP) { serviceAccess = SERVICE_STOP | SERVICE_QUERY_STATUS; wControlCode = SERVICE_CONTROL_STOP; } else if (controlCode == org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_INTERROGATE) { serviceAccess = SERVICE_INTERROGATE | SERVICE_QUERY_STATUS; wControlCode = SERVICE_CONTROL_INTERROGATE; } else if (controlCode == org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_PAUSE) { serviceAccess = SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS; wControlCode = SERVICE_CONTROL_PAUSE; } else if (controlCode == org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_CONTINUE) { serviceAccess = SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS; wControlCode = SERVICE_CONTROL_CONTINUE; } else if ((controlCode >= 128) || (controlCode <= 255)) { serviceAccess = SERVICE_USER_DEFINED_CONTROL | SERVICE_QUERY_STATUS; wControlCode = controlCode; } else { /* Illegal control code. */ _sntprintf(buffer, 512, TEXT("Illegal Control code specified: %d"), controlCode); throwServiceException(env, 1, buffer); threwError = TRUE; } if (!threwError) { hService = OpenService(hSCManager, serviceName, serviceAccess); if (hService) { /* If we are trying to start a service, it needs to be handled specially. */ if (controlCode == org_tanukisoftware_wrapper_WrapperManager_SERVICE_CONTROL_CODE_START) { if (StartService(hService, 0, NULL)) { /* Started the service. Continue on and interrogate the service. */ } else { /* Failed. */ _sntprintf(buffer, bufferSize, TEXT("Unable to start service \"%s\": %s"), serviceName, getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } } if (!threwError) { if (ControlService(hService, wControlCode, &serviceStatus)) { /* Success. fall through. */ } else { /* Failed to send the control code. See if the service is running. */ if (GetLastError() == ERROR_SERVICE_NOT_ACTIVE) { /* Service is not running, so get its status information. */ if (QueryServiceStatus(hService, &serviceStatus)) { /* We got the status. fall through. */ } else { /* Actual failure. */ _sntprintf(buffer, bufferSize, TEXT("Unable to query status of service \"%s\": %s"), serviceName, getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } } else { /* Actual failure. */ _sntprintf(buffer, bufferSize, TEXT("Unable to query status of service \"%s\": %s"), serviceName, getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } } if (!threwError) { /* Build up a service object to return. */ if (serviceClass = (*env)->FindClass(env, "org/tanukisoftware/wrapper/WrapperWin32Service")) { /* Look for the constructor. Ignore failures. */ if (constructor = (*env)->GetMethodID(env, serviceClass, "", "(Ljava/lang/String;Ljava/lang/String;II)V")) { /* Look up the display name of the service. First need to figure out how big it is. */ displayNameSize = 0; GetServiceDisplayName(hSCManager, serviceName, NULL, &displayNameSize); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { _sntprintf(buffer, bufferSize, TEXT("Unable to obtain the display name of service \"%s\": %s"), serviceName, getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } else { displayNameSize++; /* Add room for the '\0' . */ displayName = malloc(sizeof(TCHAR) * displayNameSize); if (!displayName) { throwOutOfMemoryError(env, TEXT("NSSCC1")); threwError = TRUE; } else { /* Now get the display name for real. */ if ((GetServiceDisplayName(hSCManager, serviceName, displayName, &displayNameSize) == 0) && GetLastError()) { _sntprintf(buffer, bufferSize, TEXT("Unable to obtain the display name of service \"%s\": %s"), serviceName, getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } else { /* Convert the display name to a jstring. */ jStringDisplayName = JNU_NewStringNative(env, displayName); if (jStringDisplayName) { state = serviceStatus.dwCurrentState; exitCode = serviceStatus.dwWin32ExitCode; if (exitCode == ERROR_SERVICE_SPECIFIC_ERROR) { exitCode = serviceStatus.dwServiceSpecificExitCode; } service = (*env)->NewObject(env, serviceClass, constructor, jStringServiceName, jStringDisplayName, state, exitCode); (*env)->DeleteLocalRef(env, jStringDisplayName); } } free(displayName); } } } else { /* Exception Thrown */ threwError = TRUE; } (*env)->DeleteLocalRef(env, serviceClass); } else { /* Exception Thrown */ threwError = TRUE; } } } CloseServiceHandle(hService); } else { /* Unable to open service. */ _sntprintf(buffer, bufferSize, TEXT("Unable to open the service '%s': %s"), serviceName, getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } } /* Close the handle to the service control manager database */ CloseServiceHandle(hSCManager); } else { /* Unable to open the service manager. */ _sntprintf(buffer, bufferSize, TEXT("Unable to open the Windows service control manager database: %s"), getLastErrorText()); throwServiceException(env, GetLastError(), buffer); threwError = TRUE; } free(serviceName); } else { /* Exception Thrown */ } return service; } #endif wrapper_3.5.26_src/src/conf/wrapper.conf.in100644 0 0 17552 12440202301 16035 0ustar 0 0 #encoding=UTF-8 # Configuration files must begin with a line specifying the encoding # of the the file. #******************************************************************** # Wrapper License Properties (Ignored by Community Edition) #******************************************************************** # Professional and Standard Editions of the Wrapper require a valid # License Key to start. Licenses can be purchased or a trial license # requested on the following pages: # http://wrapper.tanukisoftware.com/purchase # http://wrapper.tanukisoftware.com/trial # Include file problems can be debugged by removing the first '#' # from the following line: ##include.debug # The Wrapper will look for either of the following optional files for a # valid License Key. License Key properties can optionally be included # directly in this configuration file. #include ../conf/wrapper-license.conf #include ../conf/wrapper-license-%WRAPPER_HOST_NAME%.conf # The following property will output information about which License Key(s) # are being found, and can aid in resolving any licensing problems. #wrapper.license.debug=TRUE #******************************************************************** # Wrapper Localization #******************************************************************** # Specify the locale which the Wrapper should use. By default the system # locale is used. #wrapper.lang=en_US # en_US or ja_JP # Specify the location of the Wrapper's language resources. If these are # missing, the Wrapper will default to the en_US locale. wrapper.lang.folder=../lang #******************************************************************** # Wrapper Java Properties #******************************************************************** # Java Application # Locate the java binary on the system PATH: wrapper.java.command=java # Specify a specific java binary: #set.JAVA_HOME=/java/path #wrapper.java.command=%JAVA_HOME%/bin/java # Tell the Wrapper to log the full generated Java command line. #wrapper.java.command.loglevel=INFO # Java Main class. This class must implement the WrapperListener interface # or guarantee that the WrapperManager class is initialized. Helper # classes are provided to do this for you. See the Integration section # of the documentation for details. wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp # Java Classpath (include wrapper.jar) Add class path elements as # needed starting from 1 wrapper.java.classpath.1=../lib/wrapper.jar # Java Library Path (location of Wrapper.DLL or libwrapper.so) wrapper.java.library.path.1=../lib # Java Bits. On applicable platforms, tells the JVM to run in 32 or 64-bit mode. wrapper.java.additional.auto_bits=TRUE # Java Additional Parameters wrapper.java.additional.1= # Initial Java Heap Size (in MB) #wrapper.java.initmemory=3 # Maximum Java Heap Size (in MB) #wrapper.java.maxmemory=64 # Application parameters. Add parameters as needed starting from 1 wrapper.app.parameter.1= #******************************************************************** # Wrapper Logging Properties #******************************************************************** # Enables Debug output from the Wrapper. # wrapper.debug=TRUE # Format of output for the console. (See docs for formats) wrapper.console.format=PM # Log Level for console output. (See docs for log levels) wrapper.console.loglevel=INFO # Log file to use for wrapper output logging. wrapper.logfile=../logs/wrapper.log # Format of output for the log file. (See docs for formats) wrapper.logfile.format=LPTM # Log Level for log file output. (See docs for log levels) wrapper.logfile.loglevel=INFO # Maximum size that the log file will be allowed to grow to before # the log is rolled. Size is specified in bytes. The default value # of 0, disables log rolling. May abbreviate with the 'k' (kb) or # 'm' (mb) suffix. For example: 10m = 10 megabytes. wrapper.logfile.maxsize=0 # Maximum number of rolled log files which will be allowed before old # files are deleted. The default value of 0 implies no limit. wrapper.logfile.maxfiles=0 # Log Level for sys/event log output. (See docs for log levels) wrapper.syslog.loglevel=NONE #******************************************************************** # Wrapper General Properties #******************************************************************** # Allow for the use of non-contiguous numbered properties wrapper.ignore_sequence_gaps=TRUE # Do not start if the pid file already exists. wrapper.pidfile.strict=TRUE # Title to use when running as a console wrapper.console.title=@app.long.name@ #******************************************************************** # Wrapper JVM Checks #******************************************************************** # Detect DeadLocked Threads in the JVM. (Requires Standard Edition) wrapper.check.deadlock=TRUE wrapper.check.deadlock.interval=60 wrapper.check.deadlock.action=RESTART wrapper.check.deadlock.output=FULL # Out Of Memory detection. # Ignore -verbose:class output to avoid false positives. wrapper.filter.trigger.1000=[Loaded java.lang.OutOfMemoryError wrapper.filter.action.1000=NONE # (Simple match) wrapper.filter.trigger.1001=java.lang.OutOfMemoryError # (Only match text in stack traces if -XX:+PrintClassHistogram is being used.) #wrapper.filter.trigger.1001=Exception in thread "*" java.lang.OutOfMemoryError #wrapper.filter.allow_wildcards.1001=TRUE wrapper.filter.action.1001=RESTART wrapper.filter.message.1001=The JVM has run out of memory. #******************************************************************** # Wrapper Email Notifications. (Requires Professional Edition) #******************************************************************** # Common Event Email settings. #wrapper.event.default.email.debug=TRUE #wrapper.event.default.email.smtp.host= #wrapper.event.default.email.smtp.port=25 #wrapper.event.default.email.subject=[%WRAPPER_HOSTNAME%:%WRAPPER_NAME%:%WRAPPER_EVENT_NAME%] Event Notification #wrapper.event.default.email.sender= #wrapper.event.default.email.recipient= # Configure the log attached to event emails. #wrapper.event.default.email.attach_log=TRUE #wrapper.event.default.email.maillog.lines=50 #wrapper.event.default.email.maillog.format=LPTM #wrapper.event.default.email.maillog.loglevel=INFO # Enable specific event emails. #wrapper.event.wrapper_start.email=TRUE #wrapper.event.jvm_prelaunch.email=TRUE #wrapper.event.jvm_start.email=TRUE #wrapper.event.jvm_started.email=TRUE #wrapper.event.jvm_deadlock.email=TRUE #wrapper.event.jvm_stop.email=TRUE #wrapper.event.jvm_stopped.email=TRUE #wrapper.event.jvm_restart.email=TRUE #wrapper.event.jvm_failed_invocation.email=TRUE #wrapper.event.jvm_max_failed_invocations.email=TRUE #wrapper.event.jvm_kill.email=TRUE #wrapper.event.jvm_killed.email=TRUE #wrapper.event.jvm_unexpected_exit.email=TRUE #wrapper.event.wrapper_stop.email=TRUE # Specify custom mail content wrapper.event.jvm_restart.email.body=The JVM was restarted.\n\nPlease check on its status.\n #******************************************************************** # Wrapper Windows NT/2000/XP Service Properties #******************************************************************** # WARNING - Do not modify any of these properties when an application # using this configuration file has been installed as a service. # Please uninstall the service before modifying this section. The # service can then be reinstalled. # Name of the service wrapper.name=@app.name@ # Display name of the service wrapper.displayname=@app.long.name@ # Description of the service wrapper.description=@app.description@ # Service dependencies. Add dependencies as needed starting from 1 wrapper.ntservice.dependency.1= # Mode in which the service is installed. AUTO_START, DELAY_START or DEMAND_START wrapper.ntservice.starttype=AUTO_START # Allow the service to interact with the desktop. wrapper.ntservice.interactive=false wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperActionServer.java100644 0 0 42072 12440202301 25215 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.IOException; import java.io.InterruptedIOException; import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; import java.net.ServerSocket; import java.util.Hashtable; import org.tanukisoftware.wrapper.WrapperManager; /** * If an application instantiates an instance of this class, the JVM will * listen on the specified port for connections. When a connection is * detected, the first byte of input will be read from the socket and * then the connection will be immediately closed. An action will then * be performed based on the byte read from the stream. *

* The easiest way to invoke an action manually is to telnet to the specified * port and then type the single command key. * telnet localhost 9999, for example. *

* Valid commands include: *

    *
  • S : Shutdown cleanly.
  • *
  • H : Immediate forced shutdown.
  • *
  • R : Restart
  • *
  • D : Perform a Thread Dump
  • *
  • U : Unexpected shutdown. (Simulate a crash for testing)
  • *
  • V : Cause an access violation. (For testing)
  • *
  • G : Make the JVM appear to be hung. (For testing)
  • *
* Additional user defined actions can be defined by calling the * {@link #registerAction( byte command, Runnable action )} method. * The Wrapper project reserves the right to define any upper case * commands in the future. To avoid future conflicts, please use lower * case for user defined commands. *

* This application will work even in most deadlock situations because the * thread is in issolation from the rest of the application. If the JVM * is truely hung, this class will fail to accept connections but the * Wrapper itself will detect the hang and restart the JVM externally. *

* The following code can be used in your application to start up the * WrapperActionServer with all default actions enabled: *

 *  int port = 9999;
 *  WrapperActionServer server = new WrapperActionServer( port );
 *  server.enableShutdownAction( true );
 *  server.enableHaltExpectedAction( true );
 *  server.enableRestartAction( true );
 *  server.enableThreadDumpAction( true );
 *  server.enableHaltUnexpectedAction( true );
 *  server.enableAccessViolationAction( true );
 *  server.enableAppearHungAction( true );
 *  server.start();
 * 
* Then remember to stop the server when your application shuts down: *
 *  server.stop();
 * 
* * @author Leif Mortenson */ public class WrapperActionServer implements Runnable { /** Command to invoke a shutdown action. */ public final static byte COMMAND_SHUTDOWN = (byte)'S'; /** Command to invoke an expected halt action. */ public final static byte COMMAND_HALT_EXPECTED = (byte)'H'; /** Command to invoke a restart action. */ public final static byte COMMAND_RESTART = (byte)'R'; /** Command to invoke a thread dump action. */ public final static byte COMMAND_DUMP = (byte)'D'; /** Command to invoke an unexpected halt action. */ public final static byte COMMAND_HALT_UNEXPECTED = (byte)'U'; /** Command to invoke an access violation. */ public final static byte COMMAND_ACCESS_VIOLATION = (byte)'V'; /** Command to invoke an appear hung action. */ public final static byte COMMAND_APPEAR_HUNG = (byte)'G'; /** The address to bind the port server to. Null for any address. */ private InetAddress m_bindAddr; /** The port to listen on for connections. */ private int m_port; /** Reference to the worker thread. */ private Thread m_runner; /** Flag set when the m_runner thread has been asked to stop. */ private boolean m_runnerStop = false; /** Reference to the ServerSocket. */ private ServerSocket m_serverSocket; /** Table of all the registered actions. */ private Hashtable m_actions = new Hashtable(); /** Log channel */ private static WrapperPrintStream m_out; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates and starts WrapperActionServer instance bound to the * specified port and address. * * @param port Port on which to listen for connections. * @param bindAddress Address to bind to. */ public WrapperActionServer( int port, InetAddress bindAddress ) { m_port = port; m_bindAddr = bindAddress; m_out = new WrapperPrintStream( System.out, "WrapperActionServer: " ); } /** * Creates and starts WrapperActionServer instance bound to the * specified port. The socket will bind to all addresses and * should be concidered a security risk. * * @param port Port on which to listen for connections. */ public WrapperActionServer( int port ) { this( port, null ); } /*--------------------------------------------------------------- * Runnable Methods *-------------------------------------------------------------*/ /** * Thread which will listen for connections on the socket. */ public void run() { if ( Thread.currentThread() != m_runner ) { throw new IllegalStateException(WrapperManager.getRes().getString( "Private method." ) ); } try { while ( !m_runnerStop ) { try { int command; Socket socket = m_serverSocket.accept(); try { // Set a short timeout of 15 seconds, // so connections will be promptly closed if left idle. socket.setSoTimeout( 15000 ); // Read a single byte. command = socket.getInputStream().read(); } finally { socket.close(); } if ( command >= 0 ) { Runnable action; synchronized( m_actions ) { action = (Runnable)m_actions.get( new Integer( command ) ); } if ( action != null ) { try { action.run(); } catch ( Throwable t ) { m_out.println( WrapperManager.getRes().getString( "Error processing action." ) ); t.printStackTrace( m_out ); } } } } catch ( Throwable t ) { // Check for throwable type this way rather than with seperate catches // to work around a problem where InterruptedException can be thrown // when the compiler gives an error saying that it can't. if ( m_runnerStop && ( ( t instanceof InterruptedException ) || ( t instanceof SocketException ) || ( t instanceof InterruptedIOException ) || ( ( t instanceof IOException ) && ( t.getMessage() != null ) && ( t.getMessage().indexOf( "Bad file descriptor" ) >= 0 ) ) // Happens on shutdown on IA64 Linux. ) ) { // This is expected, the service is being stopped. } else { m_out.println( WrapperManager.getRes().getString( "Unexpected error." ) ); t.printStackTrace( m_out ); // Avoid tight thrashing try { Thread.sleep( 5000 ); } catch ( InterruptedException e ) { // Ignore } } } } } finally { synchronized( this ) { m_runner = null; // Wake up the stop method if it is waiting for the runner to stop. this.notify(); } } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Starts the runner thread. * * @throws IOException If the server socket is unable to bind to the * specified port or there are any other problems * opening a socket. */ public void start() throws IOException { // Create the server socket. m_serverSocket = new ServerSocket( m_port, 5, m_bindAddr ); m_runner = new Thread( this, "WrapperActionServer_runner" ); m_runner.setDaemon( true ); m_runner.start(); } /** * Stops the runner thread, blocking until it has stopped. */ public void stop() throws Exception { Thread runner = m_runner; m_runnerStop = true; runner.interrupt(); // Close the server socket so it stops blocking for new connections. ServerSocket serverSocket = m_serverSocket; if ( serverSocket != null ) { try { serverSocket.close(); } catch ( IOException e ) { // Ignore. } } synchronized( this ) { while( m_runner != null ) { try { // Wait to be notified that the thread has exited. this.wait(); } catch ( InterruptedException e ) { // Ignore } } } } /** * Registers an action with the action server. The server will not accept * any new connections until an action has returned, so keep that in mind * when writing them. Also be aware than any uncaught exceptions will be * dumped to the console if uncaught by the action. To avoid this, wrap * the code in a try { ... } catch (Throwable t) { ... } * block. * * @param command Command to be registered. Will override any exiting * action already registered with the same command. * @param action Action to be registered. */ public void registerAction( byte command, Runnable action ) { synchronized( m_actions ) { m_actions.put( new Integer( command ), action ); } } /** * Unregisters an action with the given command. If no action exists with * the specified command, the method will quietly ignore the call. */ public void unregisterAction( byte command ) { synchronized( m_actions ) { m_actions.remove( new Integer( command ) ); } } /** * Enable or disable the shutdown command. Disabled by default. * * @param enable True to enable to action, false to disable it. */ public void enableShutdownAction( boolean enable ) { if ( enable ) { registerAction( COMMAND_SHUTDOWN, new Runnable() { public void run() { WrapperManager.stopAndReturn( 0 ); } } ); } else { unregisterAction( COMMAND_SHUTDOWN ); } } /** * Enable or disable the expected halt command. Disabled by default. * This will shutdown the JVM, but will do so immediately without going * through the clean shutdown process. * * @param enable True to enable to action, false to disable it. */ public void enableHaltExpectedAction( boolean enable ) { if ( enable ) { registerAction( COMMAND_HALT_EXPECTED, new Runnable() { public void run() { WrapperManager.stopImmediate( 0 ); } } ); } else { unregisterAction( COMMAND_HALT_EXPECTED ); } } /** * Enable or disable the restart command. Disabled by default. * * @param enable True to enable to action, false to disable it. */ public void enableRestartAction( boolean enable ) { if ( enable ) { registerAction( COMMAND_RESTART, new Runnable() { public void run() { WrapperManager.restartAndReturn(); } } ); } else { unregisterAction( COMMAND_RESTART ); } } /** * Enable or disable the thread dump command. Disabled by default. * * @param enable True to enable to action, false to disable it. */ public void enableThreadDumpAction( boolean enable ) { if ( enable ) { registerAction( COMMAND_DUMP, new Runnable() { public void run() { WrapperManager.requestThreadDump(); } } ); } else { unregisterAction( COMMAND_DUMP ); } } /** * Enable or disable the unexpected halt command. Disabled by default. * If this command is executed, the Wrapper will think the JVM crashed * and restart it. * * @param enable True to enable to action, false to disable it. */ public void enableHaltUnexpectedAction( boolean enable ) { if ( enable ) { registerAction( COMMAND_HALT_UNEXPECTED, new Runnable() { public void run() { Runtime.getRuntime().halt( 0 ); } } ); } else { unregisterAction( COMMAND_HALT_UNEXPECTED ); } } /** * Enable or disable the access violation command. Disabled by default. * This command is useful for testing how an application handles the worst * case situation where the JVM suddenly crashed. When this happens, the * the JVM will simply die and there will be absolutely no chance for any * shutdown or cleanup work to be done by the JVM. * * @param enable True to enable to action, false to disable it. */ public void enableAccessViolationAction( boolean enable ) { if ( enable ) { registerAction( COMMAND_ACCESS_VIOLATION, new Runnable() { public void run() { WrapperManager.accessViolationNative(); } } ); } else { unregisterAction( COMMAND_ACCESS_VIOLATION ); } } /** * Enable or disable the appear hung command. Disabled by default. * This command is useful for testing how an application handles the * situation where the JVM stops responding to the Wrapper's ping * requests. This can happen if the JVM hangs or some piece of code * deadlocks. When this happens, the Wrapper will give up after the * ping timeout has expired and kill the JVM process. The JVM will * not have a chance to clean up and shudown gracefully. * * @param enable True to enable to action, false to disable it. */ public void enableAppearHungAction( boolean enable ) { if ( enable ) { registerAction( COMMAND_APPEAR_HUNG, new Runnable() { public void run() { WrapperManager.appearHung(); } } ); } else { unregisterAction( COMMAND_APPEAR_HUNG ); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperGroup.java100644 0 0 2466 12440202301 23670 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * A WrapperGroup contains information about a group which a user * belongs to. A WrapperGroup is obtained via a WrapperUser. * * @author Leif Mortenson */ public abstract class WrapperGroup { /* The name of the group. */ private String m_group; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ WrapperGroup( String group ) { // Decode the parameters using the default system encoding. m_group = group; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the name of the group. * * @return The name of the group. */ public String getGroup() { return m_group; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperInfo.java100644 0 0 6540 12440202301 23464 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.org/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.util.Calendar; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.text.ParseException; /** * WrapperInfo.java is build as part of the build process and should not be * modified. Any changes to this class should be made to WrapperInfo.java.in * * @author Leif Mortenson */ final class WrapperInfo { /** Version of the Wrapper. */ private static final String m_version = "3.5.26"; /** Date that the Wrapper was built. */ private static final Calendar m_build = Calendar.getInstance(); /** Static initializer to create the build calendar from info hardcoded * during the build. */ static { Calendar buildDate = Calendar.getInstance(); Calendar buildTime = Calendar.getInstance(); try { buildDate.setTime( new SimpleDateFormat( "yyyyMMdd" ).parse( "20141205" ) ); buildTime.setTime( new SimpleDateFormat( "HHmm" ).parse( "1005" ) ); m_build.set( buildDate.get( Calendar.YEAR ), buildDate.get( Calendar.MONTH ), buildDate.get( Calendar.DATE ), buildTime.get( Calendar.HOUR_OF_DAY ), buildTime.get( Calendar.MINUTE ) ); } catch ( ParseException e ) { System.out.println( "WrapperInfo: Can not parse build date: " + e.getMessage() ); } } /** * Returns the version of the Wrapper. * * @return the version of the Wrapper. */ static String getVersion() { return m_version; } /** * Returns the time that the Wrapper was built. * * @return The time that the Wrapper was built. */ static String getBuildTime() { DateFormat df = new SimpleDateFormat( "HH:mm zz MMM d, yyyy" ); return df.format( m_build.getTime() ); } /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Can not be instantiated. */ private WrapperInfo() { } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperInfo.java.in100644 0 0 6736 12440202300 24077 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.org/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.util.Calendar; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.text.ParseException; /** * WrapperInfo.java is build as part of the build process and should not be * modified. Any changes to this class should be made to WrapperInfo.java.in * * @author Leif Mortenson */ final class WrapperInfo { /** Version of the Wrapper. */ private static final String m_version = "@version.root@"; /** Date that the Wrapper was built. */ private static final Calendar m_build = Calendar.getInstance(); /** Static initializer to create the build calendar from info hardcoded * during the build. */ static { Calendar buildDate = Calendar.getInstance(); Calendar buildTime = Calendar.getInstance(); try { buildDate.setTime( new SimpleDateFormat( "yyyyMMdd" ).parse( "@build.date@" ) ); buildTime.setTime( new SimpleDateFormat( "HHmm" ).parse( "@build.time@" ) ); m_build.set( buildDate.get( Calendar.YEAR ), buildDate.get( Calendar.MONTH ), buildDate.get( Calendar.DATE ), buildTime.get( Calendar.HOUR_OF_DAY ), buildTime.get( Calendar.MINUTE ) ); } catch ( ParseException e ) { System.out.println( "WrapperInfo: Can not parse build date: " + e.getMessage() ); } } /** * Returns the version of the Wrapper. * * @return the version of the Wrapper. */ static String getVersion() { return m_version; } /** * Returns the time that the Wrapper was built. * * @return The time that the Wrapper was built. */ static String getBuildTime() { DateFormat df = new SimpleDateFormat( "HH:mm zz MMM d, yyyy" ); return df.format( m_build.getTime() ); } /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Can not be instantiated. */ private WrapperInfo() { } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperJNIError.java100644 0 0 3242 12440202301 24217 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperJNIErrors are thrown when user code encounters problems accessing * native Wrapper features. * * @author Leif Mortenson */ public class WrapperJNIError extends Error { /** * Serial Version UID. */ private static final long serialVersionUID = 4163224795268336447L; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperJNIError. * * @param message Message describing the exception. */ WrapperJNIError( String message ) { super( message ); } /** * Creates a new WrapperJNIError. * * @param message Message describing the exception. */ WrapperJNIError( byte[] message ) { this( new String( message ) ); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Return string representation of the Error. * * @return String representation of the Error. */ public String toString() { return this.getClass().getName() + " " + getMessage(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperJarApp.java100644 0 0 74222 12440202301 23770 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.StringTokenizer; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; /** * By default the WrapperJarApp will only wait for 2 seconds for the main * method of the start class to complete. This was done because the main * methods of many applications never return. It is possible to force the * class to wait for the startup main method to complete by defining the * following system property when launching the JVM (defaults to FALSE): * -Dorg.tanukisoftware.wrapper.WrapperJarApp.waitForStartMain=TRUE *

* Using the waitForStartMain property will cause the startup to wait * indefinitely. This is fine if the main method will always return * within a predefined period of time. But if there is any chance that * it could hang, then the maxStartMainWait property may be a better * option. It allows the 2 second wait time to be overridden. To wait * for up to 5 minutes for the startup main method to complete, set * the property to 300 as follows (defaults to 2 seconds): * -Dorg.tanukisoftware.wrapper.WrapperJarApp.maxStartMainWait=300 *

* By default, the WrapperJarApp will tell the Wrapper to exit with an * exit code of 1 if any uncaught exceptions are thrown in the configured * main method. This is good in most cases, but is a little different than * the way Java works on its own. Java will stay up and running if it has * launched any other non-daemon threads even if the main method ends because * of an uncaught exception. To get this same behavior, it is possible to * specify the following system property when launching the JVM (defaults to * FALSE): * -Dorg.tanukisoftware.wrapper.WrapperJarApp.ignoreMainExceptions=TRUE *

* It is possible to extend this class but make absolutely sure that any * overridden methods call their super method or the class will fail to * function correctly. Most users will have no need to override this * class. Remember that if overridden, the main method will also need to * be recreated in the child class to make sure that the correct instance * is created. *

* NOTE - The main methods of many applications are designed not to * return. In these cases, you must either stick with the default 2 second * startup timeout or specify a slightly longer timeout, using the * maxStartMainWait property, to simulate the amount of time your application * takes to start up. *

* WARNING - If the waitForStartMain is specified for an application * whose start method never returns, the Wrapper will appear at first to be * functioning correctly. However the Wrapper will never enter a running * state, this means that the Windows Service Manager and several of the * Wrapper's error recovery mechanisms will not function correctly. * * @author Leif Mortenson */ public class WrapperJarApp implements WrapperListener, Runnable { /** Info level log channel */ private static WrapperPrintStream m_outInfo; /** Error level log channel */ private static WrapperPrintStream m_outError; /** Debug level log channel */ private static WrapperPrintStream m_outDebug; /** * Application's main method */ private Method m_mainMethod; /** * Command line arguments to be passed on to the application */ private String[] m_appArgs; /** * Gets set to true when the thread used to launch the application * actuially starts. */ private boolean m_mainStarted; /** * Gets set to true when the thread used to launch the application * completes. */ private boolean m_mainComplete; /** * Exit code to be returned if the application fails to start. */ private Integer m_mainExitCode; /** * True if uncaught exceptions in the user app's main method should be ignored. */ private boolean m_ignoreMainExceptions; /** * Flag used to signify that the start method has completed. */ private boolean m_startComplete; /** * Flag that is set if there were any initialization problems. */ private boolean m_initFailed; /** * Error message which should be shown if initialization Failed. */ private String m_initError; /** * True if usage should be shown as part of an initialization error. */ private boolean m_initShowUsage; /** * The exception which caused the error. Only needs to be set if the stacktrace is required. */ private Throwable m_initException; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates an instance of a WrapperJarApp. * * @param args The full list of arguments passed to the JVM. */ protected WrapperJarApp( String args[] ) { // Initialize the WrapperManager class on startup by referencing it. Class wmClass = WrapperManager.class; // Set up some log channels m_outInfo = new WrapperPrintStream( System.out, "WrapperJarApp: " ); m_outError = new WrapperPrintStream( System.out, "WrapperJarApp Error: " ); m_outDebug = new WrapperPrintStream( System.out, "WrapperJarApp Debug: " ); // Do all of our initialization here so the modified array list which is passed // to the WrapperListener.start method can remain unchanged. Ideally we would // want to handle this within the start method, but that would be an API change // that could effect users. // appArgs will be an args array with the jar file name stripped off. String[] appArgs; // Get the jar file name of the application if ( args.length < 1 ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Not enough argments. Minimum {0} required.", "1" ); m_initShowUsage = true; // No jar file name, do the best we can for now. appArgs = new String[0]; } else { // Look for the specified jar file. File file = new File( args[0] ); if ( !file.exists() ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate the jar file {0}", args[0] ); m_initShowUsage = true; } else { File parent = file.getParentFile(); JarFile jarFile; try { jarFile = new JarFile( file ); } catch ( IOException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to open the jar file {0} : {1}", args[0], e ); jarFile = null; } if ( !m_initFailed ) { Manifest manifest; try { manifest = jarFile.getManifest(); } catch ( IOException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to access the jar''s manifest file {0} : {1}", args[0], e ); manifest = null; } if ( !m_initFailed ) { Attributes attributes = manifest.getMainAttributes(); String mainClassName = attributes.getValue( "Main-Class" ); if ( mainClassName == null ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "The Main-Class was not specified correctly in the jar file''s manifest file. Please make sure all required meta information is being set." ); /* no main class, no chance this will ever do something sensible, so stop here now */ } else { String classPath = attributes.getValue( "Class-Path" ); if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( "Jar Main-Class: " + mainClassName ); } URL[] classURLs; if ( ( classPath != null ) && ( !classPath.equals( "" ) ) ) { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString("Jar Classpath: {0}", classPath ) ); } StringTokenizer st = new StringTokenizer( classPath, " \n\r" ); classURLs = new URL[st.countTokens() + 1]; // Store the main jar in the classpath. try { classURLs[0] = new URL( "file:" + file.getAbsolutePath() ); } catch ( MalformedURLException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to add jar to classpath: {0}", e ); } if ( !m_initFailed ) { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString(" Classpath[0]=") + classURLs[0] ); } // Add any other jars in the manifest classpath relative to the location of the main jar. for ( int i = 1; st.hasMoreTokens(); i++ ) { String classEntry = st.nextToken(); try { classURLs[i] = new URL( "file:" + new File( parent, classEntry).getAbsolutePath() ); } catch ( MalformedURLException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Malformed classpath in the jar''s manifest file {0} : {1}", args[0], e ); } if ( !m_initFailed ) { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString(" Classpath[{0}]=", new Integer( i ) ) + classURLs[i] ); } } } } } else { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "Jar Classpath: Not specified." ) ); } classURLs = new URL[1]; // Store the main jar in the classpath. try { classURLs[0] = new URL( "file:" + file.getAbsolutePath() ); } catch ( MalformedURLException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to add jar to classpath: {0}", e ); } if ( !m_initFailed ) { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( " Classpath[0]=" ) + classURLs[0] ); } } } if ( !m_initFailed ) { URLClassLoader cl = URLClassLoader.newInstance( classURLs, this.getClass().getClassLoader() ); // Look for the specified class by name Class mainClass; try { mainClass = Class.forName( mainClassName, true, cl ); } catch ( ClassNotFoundException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate the class {0} : {1}", mainClassName, e ); mainClass = null; } catch ( ExceptionInInitializerError e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Class {0} found but could not be initialized due to:", mainClassName ); m_initException = e; mainClass = null; } catch ( LinkageError e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Class {0} found but could not be initialized: {1}", mainClassName, e ); mainClass = null; } if ( !m_initFailed ) { // Look for the main method try { // getDeclaredMethod will return any method named main in the specified class, // while getMethod will only return public methods, but it will search up the // inheritance path. m_mainMethod = mainClass.getMethod( "main", new Class[] { String[].class } ); } catch ( NoSuchMethodException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate a public static main method in class {0} : {1}", args[0] , e ); } catch ( SecurityException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate a public static main method in class {0} : {1}", args[0], e ); } if ( !m_initFailed ) { // Make sure that the method is public and static int modifiers = m_mainMethod.getModifiers(); if ( !( Modifier.isPublic( modifiers ) && Modifier.isStatic( modifiers ) ) ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "The main method in class {0} must be declared public and static.", args[0] ); } } } } } } } } // Strip the jar file name off of the args list. // This is assuming the jar file name was valid for now. appArgs = new String[args.length - 1]; System.arraycopy( args, 1, appArgs, 0, appArgs.length ); } // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start( this, appArgs ); // This thread ends, the WrapperManager will start the application after the Wrapper has // been properly initialized by calling the start method above. } /*--------------------------------------------------------------- * Runnable Methods *-------------------------------------------------------------*/ /** * Used to launch the application in a separate thread. */ public void run() { // Notify the start method that the thread has been started by the JVM. synchronized( this ) { m_mainStarted = true; notifyAll(); } Throwable t = null; try { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString("invoking main method" ) ); } try { m_mainMethod.invoke( null, new Object[] { m_appArgs } ); } finally { // Make sure the rest of this thread does not fall behind the application. Thread.currentThread().setPriority( Thread.MAX_PRIORITY ); } if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString("main method completed" ) ); } synchronized(this) { // Let the start() method know that the main method returned, in case it is // still waiting. m_mainComplete = true; this.notifyAll(); } return; } catch ( IllegalAccessException e ) { t = e; } catch ( IllegalArgumentException e ) { t = e; } catch ( InvocationTargetException e ) { t = e.getTargetException(); if ( t == null ) { t = e; } } // If we get here, then an error was thrown. If this happened quickly // enough, the start method should be allowed to shut things down. m_outInfo.println(); m_outError.println( WrapperManager.getRes().getString( "Encountered an error running main:" ) ); // We should print a stack trace here, because in the case of an // InvocationTargetException, the user needs to know what exception // their app threw. t.printStackTrace( m_outError ); synchronized( this ) { if ( m_ignoreMainExceptions ) { if ( !m_startComplete ) { // An exception was thrown, but we want to let the application continue. m_mainComplete = true; this.notifyAll(); } return; } else { if ( m_startComplete ) { // Shut down here. WrapperManager.stop( 1 ); return; // Will not get here. } else { // Let start method handle shutdown. m_mainComplete = true; m_mainExitCode = new Integer( 1 ); this.notifyAll(); return; } } } } /*--------------------------------------------------------------- * WrapperListener Methods *-------------------------------------------------------------*/ /** * The start method is called when the WrapperManager is signalled by the * native wrapper code that it can start its application. This * method call is expected to return, so a new thread should be launched * if necessary. * If there are any problems, then an Integer should be returned, set to * the desired exit code. If the application should continue, * return null. */ public Integer start( String[] args ) { // See if there were any startup problems. if ( m_initFailed ) { if ( m_initError != null ) { m_outError.println( m_initError ); } if ( m_initException != null ) { m_initException.printStackTrace( m_outError ); } if ( m_initShowUsage ) { showUsage(); } return new Integer( 1 ); } // Decide whether or not to wait for the start main method to complete before returning. boolean waitForStartMain = WrapperSystemPropertyUtil.getBooleanProperty( WrapperJarApp.class.getName() + ".waitForStartMain", false ); m_ignoreMainExceptions = WrapperSystemPropertyUtil.getBooleanProperty( WrapperJarApp.class.getName() + ".ignoreMainExceptions", false ); int maxStartMainWait = WrapperSystemPropertyUtil.getIntProperty( WrapperJarApp.class.getName() + ".maxStartMainWait", 2 ); maxStartMainWait = Math.max( 1, maxStartMainWait ); // Decide the maximum number of times to loop waiting for the main start method. int maxLoops; if ( waitForStartMain ) { maxLoops = Integer.MAX_VALUE; if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) Will wait indefinitely for the main method to complete." ) ); } } else { maxLoops = maxStartMainWait; // 1s loops. if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) Will wait up to {0} seconds for the main method to complete.", new Integer( maxLoops ) ) ); } } Thread mainThread = new Thread( this, "WrapperJarAppMain" ); synchronized(this) { m_appArgs = args; mainThread.start(); // Make sure the rest of this thread does not fall behind the application. Thread.currentThread().setPriority( Thread.MAX_PRIORITY ); // To avoid problems with the main thread starting slowly on heavily loaded systems, // do not continue until the thread has actually started. while ( !m_mainStarted ) { try { this.wait( 1000 ); } catch ( InterruptedException e ) { // Continue. } } // Wait for startup main method to complete. int loops = 0; while ( ( loops < maxLoops ) && ( !m_mainComplete ) ) { try { this.wait( 1000 ); } catch ( InterruptedException e ) { // Continue. } if ( !m_mainComplete ) { // If maxLoops is large then this could take a while. Notify the // WrapperManager that we are still starting so it doesn't give up. WrapperManager.signalStarting( 5000 ); } loops++; } // Always set the flag stating that the start method completed. This is needed // so the run method can decide whether or not it needs to be responsible for // shutting down the JVM in the event of an exception thrown by the start main // method. m_startComplete = true; // The main exit code will be null unless an error was thrown by the start // main method. if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) end. Main Completed={0}, exitCode={1}", new Boolean( m_mainComplete ), m_mainExitCode ) ); } return m_mainExitCode; } } /** * Called when the application is shutting down. */ public int stop( int exitCode ) { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( "stop(" + exitCode + ")" ); } // Normally an application will be asked to shutdown here. Standard Java applications do // not have shutdown hooks, so do nothing here. It will be as if the user hit CTRL-C to // kill the application. return exitCode; } /** * Called whenever the native wrapper code traps a system control signal * against the Java process. It is up to the callback to take any actions * necessary. Possible values are: WrapperManager.WRAPPER_CTRL_C_EVENT, * WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, or * WRAPPER_CTRL_SHUTDOWN_EVENT */ public void controlEvent( int event ) { if ( ( event == WrapperManager.WRAPPER_CTRL_LOGOFF_EVENT ) && ( WrapperManager.isLaunchedAsService() || WrapperManager.isIgnoreUserLogoffs() ) ) { // Ignore m_outInfo.println( WrapperManager.getRes().getString("User logged out. Ignored." ) ); } else { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println(WrapperManager.getRes().getString( "controlEvent({0}) Stopping", new Integer( event ) ) ); } WrapperManager.stop( 0 ); // Will not get here. } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Displays application usage */ protected void showUsage() { // Show this output without headers. System.out.println(); System.out.println( WrapperManager.getRes().getString( "WrapperJarApp Usage:" ) ); System.out.println( WrapperManager.getRes().getString( " java org.tanukisoftware.wrapper.WrapperJarApp {jar_file} [app_arguments]" ) ); System.out.println(); System.out.println( WrapperManager.getRes().getString( "Where:" ) ); System.out.println( WrapperManager.getRes().getString( " jar_file: The jar file to run." ) ); System.out.println( WrapperManager.getRes().getString( " app_arguments: The arguments that would normally be passed to the" ) ); System.out.println( WrapperManager.getRes().getString( " application." ) ); } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ /** * Used to Wrapper enable a standard Java application. This main * expects the first argument to be the class name of the application * to launch. All remaining arguments will be wrapped into a new * argument list and passed to the main method of the specified * application. * * @param args Arguments passed to the application. */ public static void main( String args[] ) { new WrapperJarApp( args ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperLicenseError.java100644 0 0 1312 12440202301 25155 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ public class WrapperLicenseError extends Error { /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ WrapperLicenseError( String message ) { super( message ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperListener.java100644 0 0 17351 12440202301 24400 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * Applications which need to be controlled directly as a service can implement * the WrapperListener interface and then register themselves with the * WrapperManager on instantiation. The WrapperManager will then control the * the class as a service for its entire life-cycle. * * @author Leif Mortenson */ public interface WrapperListener { /** * The start method is called when the WrapperManager is signaled by the * native wrapper code that it can start its application. This * method call is expected to return, so a new thread should be launched * if necessary. *

* If this method throws an exception the Wrapper will shutdown the current * JVM in an error state and then relaunch a new JVM. It is the * responsibility of the user code to catch any exceptions and return an * appropriate exit code if the exception should result in the Wrapper * stopping. * * @param args List of arguments used to initialize the application. * * @return Any error code if the application should exit on completion * of the start method. If there were no problems then this * method should return null. */ Integer start( String[] args ); /** * Called when the application is shutting down. The Wrapper assumes that * this method will return fairly quickly. If the shutdown code code * could potentially take a long time, then WrapperManager.signalStopping() * should be called to extend the timeout period. If for some reason, * the stop method can not return, then it must call * WrapperManager.stopped() to avoid warning messages from the Wrapper. *

* By default, the stop() method will only be called if the start() method * has completed and returned null. There are however cases in which the * stop method should be called on shutdown even if the start method has * not returned or returned an exit code. This functionality can be * enabled by setting the following property in the Wrapper configuration * file: wrapper.listener.force_stop=TRUE. *

* WARNING - Directly calling System.exit in this method will result in * a deadlock in cases where this method is called from within a shutdown * hook. This method will be invoked by a shutdown hook if the JVM * shutdown was originally initiated by a call to System.exit. * * @param exitCode The suggested exit code that will be returned to the OS * when the JVM exits. If WrapperManager.stop was called * to stop the JVM then this exit code will reflect that * value. However, if System.exit or Runtime.halt were * used then this exitCode will always be 0. In these * cases, the Wrapper process will be able to detect the * actual JVM exit code and handle it correctly. * * @return The exit code to actually return to the OS. In most cases, this * should just be the value of exitCode, however the user code has * the option of changing the exit code if there are any problems * during shutdown. */ int stop( int exitCode ); /** * Called whenever the native wrapper code traps a system control signal * against the Java process. It is up to the callback to take any actions * necessary. Possible values are: WrapperManager.WRAPPER_CTRL_C_EVENT, * WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, * WRAPPER_CTRL_SHUTDOWN_EVENT, WRAPPER_CTRL_TERM_EVENT, or * WRAPPER_CTRL_HUP_EVENT. *

* The WRAPPER_CTRL_C_EVENT will be called whether or not the JVM is * controlled by the Wrapper. If controlled by the Wrapper, it is * undetermined as to whether the Wrapper or the JVM will receive this * signal first, but the Wrapper will always initiate a shutdown. In * most cases, the implementation of this method should call * WrapperManager.stop() to initiate a shutdown from within the JVM. * The WrapperManager will always handle the shutdown correctly whether * shutdown is initiated from the Wrapper, within the JVM or both. * By calling stop here, it will ensure that the application will behave * correctly when run standalone, without the Wrapper. *

* WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, and * WRAPPER_CTRL_SHUTDOWN_EVENT events will only be encountered on Windows * systems. Like the WRAPPER_CTRL_C_EVENT event, it is undetermined as to * whether the Wrapper or JVM will receive the signal first. All signals * will be triggered by the OS whether the JVM is being run as an NT * service or as a console application. If the JVM is running as a * console application, the Application must respond to the CLOSE and * LOGOFF events by calling WrapperManager.stop() in a timely manner. * In these cases, Windows will wait for the JVM process to exit before * moving on to signal the next process. If the JVM process does not exit * within a reasonable amount of time, Windows will pop up a message box * for the user asking if they wish to wait for the process or exit or * forcibly close it. The JVM must call stop() in response to the * SHUTDOWN method whether running as a console or NT service. Usually, * the LOGOFF event should be ignored when the Wrapper is running as an * NT service. *

* WRAPPER_CTRL_TERM_EVENT events will only be encountered on UNIX systems. *

* If the wrapper.ignore_signals property is set to TRUE then any * WRAPPER_CTRL_C_EVENT, WRAPPER_CTRL_CLOSE_EVENT, * WRAPPER_CTRL_TERM_EVENT, or WRAPPER_CTRL_HUP_EVENT * events will be blocked prior to this method being called. *

* Unless you know what you are doing, it is suggested that the body of * this method contain the following code, or its functional equivalent. *

     *   public void controlEvent( int event )
     *   {
     *       if ( ( event == WrapperManager.WRAPPER_CTRL_LOGOFF_EVENT )
     *           && ( WrapperManager.isLaunchedAsService() || WrapperManager.isIgnoreUserLogoffs() ) )
     *       {
     *           // Ignore
     *       }
     *       else
     *       {
     *           WrapperManager.stop( 0 );
     *       }
     *   }
     * 
* * @param event The system control signal. */ void controlEvent( int event ); } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperManager.java100644 0 0 723653 12440202301 24216 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2010 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.BindException; import java.net.ConnectException; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.net.URL; import java.security.CodeSource; import java.security.AccessControlException; import java.security.AccessController; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.ResourceBundle; import java.util.Locale; import java.util.MissingResourceException; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.tanukisoftware.wrapper.event.WrapperControlEvent; import org.tanukisoftware.wrapper.event.WrapperEvent; import org.tanukisoftware.wrapper.event.WrapperEventListener; import org.tanukisoftware.wrapper.event.WrapperLogFileChangedEvent; import org.tanukisoftware.wrapper.event.WrapperPingEvent; import org.tanukisoftware.wrapper.event.WrapperServiceActionEvent; import org.tanukisoftware.wrapper.event.WrapperServiceControlEvent; import org.tanukisoftware.wrapper.event.WrapperServicePauseEvent; import org.tanukisoftware.wrapper.event.WrapperServiceResumeEvent; import org.tanukisoftware.wrapper.event.WrapperTickEvent; import org.tanukisoftware.wrapper.security.WrapperEventPermission; import org.tanukisoftware.wrapper.security.WrapperPermission; import org.tanukisoftware.wrapper.security.WrapperServicePermission; import org.tanukisoftware.wrapper.security.WrapperUserEventPermission; /** * Handles all communication with the native portion of the Wrapper code. * Communication takes place either over a Pipe, or Socket. In either * case, the Wrapper code will initializate its end of the communication * and then launch Java in a separate process. * * In the case of a socket, the Wrapper will set up a server socket which * the Java code is expected to open a socket to on startup. When the * server socket is created, a port will be chosen depending on what is * available to the system. This port will then be passed to the Java * process as property named "wrapper.port". * * In the case of a pipe, the Wrapper will set up a pair of named ports * and then pass in a property named "wrapper.backend=pipe". The Wrapper * and JVM will communicate via the pipes. * * For security reasons, the native code will only allow connections from * localhost and will expect to receive the key specified in a property * named "wrapper.key". * * When the backend connection is a socket, it does not have any timeout * set by default. For testing purposes it is possible to set a timeout * in seconds using the following system property when launching the JVM. * This will only be noticeable if it is shorter than the ping interval, * and debug output is enabled: * -Dwrapper.backend.so_timeout=300 * * This class is implemented as a singleton class. * * Generate JNI Headers with the following command in the build/classes * directory: * javah -jni -classpath ./ org.tanukisoftware.wrapper.WrapperManager * * @author Leif Mortenson */ public final class WrapperManager implements Runnable { private static final String WRAPPER_CONNECTION_THREAD_NAME = "Wrapper-Connection"; private static final int DEFAULT_PORT = 15003; private static final int DEFAULT_CPU_TIMEOUT = 10000; /** The number of milliseconds in one tick. Used for internal system * time independent time keeping. */ private static final int TICK_MS = 100; private static final int TIMER_FAST_THRESHOLD = 2 * 24 * 3600 * 1000 / TICK_MS; // 2 days. private static final int TIMER_SLOW_THRESHOLD = 2 * 24 * 3600 * 1000 / TICK_MS; // 2 days. /** * Backend server can be of 3 types: socket IPv4, socket IPv6 or pipe */ private static final int BACKEND_TYPE_UNKNOWN = 0; private static final int BACKEND_TYPE_SOCKET_V4 = 0x01; private static final int BACKEND_TYPE_SOCKET_V6 = 0x02; private static final int BACKEND_TYPE_PIPE = 0x04; private static final byte WRAPPER_MSG_START = (byte)100; private static final byte WRAPPER_MSG_STOP = (byte)101; private static final byte WRAPPER_MSG_RESTART = (byte)102; private static final byte WRAPPER_MSG_PING = (byte)103; private static final byte WRAPPER_MSG_STOP_PENDING = (byte)104; private static final byte WRAPPER_MSG_START_PENDING = (byte)105; private static final byte WRAPPER_MSG_STARTED = (byte)106; private static final byte WRAPPER_MSG_STOPPED = (byte)107; private static final byte WRAPPER_MSG_KEY = (byte)110; private static final byte WRAPPER_MSG_BADKEY = (byte)111; private static final byte WRAPPER_MSG_LOW_LOG_LEVEL = (byte)112; private static final byte WRAPPER_MSG_PING_TIMEOUT = (byte)113; /* No longer used. */ private static final byte WRAPPER_MSG_SERVICE_CONTROL_CODE = (byte)114; private static final byte WRAPPER_MSG_PROPERTIES = (byte)115; /** Log commands are actually 116 + the LOG LEVEL. */ private static final byte WRAPPER_MSG_LOG = (byte)116; private static final byte WRAPPER_MSG_CHILD_LAUNCH = (byte)132; private static final byte WRAPPER_MSG_CHILD_TERM = (byte)133; private static final byte WRAPPER_MSG_LOGFILE = (byte)134; private static final byte WRAPPER_MSG_CHECK_DEADLOCK = (byte)135; private static final byte WRAPPER_MSG_DEADLOCK = (byte)136; private static final byte WRAPPER_MSG_APPEAR_ORPHAN = (byte)137; /* No longer used. */ private static final byte WRAPPER_MSG_PAUSE = (byte)138; private static final byte WRAPPER_MSG_RESUME = (byte)139; private static final byte WRAPPER_MSG_GC = (byte)140; private static final byte WRAPPER_MSG_FIRE_USER_EVENT= (byte)141; /** Received when the user presses CTRL-C in the console on Windows or UNIX platforms. */ public static final int WRAPPER_CTRL_C_EVENT = 200; /** Received when the user clicks on the close button of a Console on Windows. */ public static final int WRAPPER_CTRL_CLOSE_EVENT = 201; /** Received when the user logs off of a Windows system. */ public static final int WRAPPER_CTRL_LOGOFF_EVENT = 202; /** Received when a Windows system is shutting down. */ public static final int WRAPPER_CTRL_SHUTDOWN_EVENT = 203; /** Received when a SIG TERM is received on a UNIX system. */ public static final int WRAPPER_CTRL_TERM_EVENT = 204; /** Received when a SIG HUP is received on a UNIX system. */ public static final int WRAPPER_CTRL_HUP_EVENT = 205; /** Received when a SIG USR1 is received on a UNIX system. */ public static final int WRAPPER_CTRL_USR1_EVENT = 206; /** Received when a SIG USR2 is received on a UNIX system. */ public static final int WRAPPER_CTRL_USR2_EVENT = 207; /** Log message at debug log level. */ public static final int WRAPPER_LOG_LEVEL_DEBUG = 1; /** Log message at info log level. */ public static final int WRAPPER_LOG_LEVEL_INFO = 2; /** Log message at status log level. */ public static final int WRAPPER_LOG_LEVEL_STATUS = 3; /** Log message at warn log level. */ public static final int WRAPPER_LOG_LEVEL_WARN = 4; /** Log message at error log level. */ public static final int WRAPPER_LOG_LEVEL_ERROR = 5; /** Log message at fatal log level. */ public static final int WRAPPER_LOG_LEVEL_FATAL = 6; /** Log message at advice log level. */ public static final int WRAPPER_LOG_LEVEL_ADVICE = 7; /** Log message at notice log level. */ public static final int WRAPPER_LOG_LEVEL_NOTICE = 8; /** Service Control code which can be sent to start a service. */ public static final int SERVICE_CONTROL_CODE_START = 0x10000; /** Service Control code which can be sent or received to stop a service. */ public static final int SERVICE_CONTROL_CODE_STOP = 1; /** Service Control code which can be sent to pause a service. */ public static final int SERVICE_CONTROL_CODE_PAUSE = 2; /** Service Control code which can be sent to resume a paused service. */ public static final int SERVICE_CONTROL_CODE_CONTINUE = 3; /** Service Control code which can be sent to or received interrogate the status of a service. */ public static final int SERVICE_CONTROL_CODE_INTERROGATE = 4; /** Service Control code which can be received when the system is shutting down. */ public static final int SERVICE_CONTROL_CODE_SHUTDOWN = 5; /** Service Control code which is received when the system being suspended. */ public static final int SERVICE_CONTROL_CODE_POWEREVENT_QUERYSUSPEND = 0x0D00; /** Service Control code which is received when permission to suspend the * computer was denied by a process. Support for this event was removed * from the Windows OS starting with Vista.*/ public static final int SERVICE_CONTROL_CODE_POWEREVENT_QUERYSUSPENDFAILED = 0x0D02; /** Service Control code which is received when the computer is about to * enter a suspended state. */ public static final int SERVICE_CONTROL_CODE_POWEREVENT_SUSPEND = 0x0D04; /** Service Control code which is received when the system has resumed * operation. This event can indicate that some or all applications did * not receive a SERVICE_CONTROL_CODE_POWEREVENT_SUSPEND event. * Support for this event was removed from the Windows OS starting with * Vista. See SERVICE_CONTROL_CODE_POWEREVENT_RESUMEAUTOMATIC. */ public static final int SERVICE_CONTROL_CODE_POWEREVENT_RESUMECRITICAL = 0x0D06; /** Service Control code which is received when the system has resumed * operation after being suspended. */ public static final int SERVICE_CONTROL_CODE_POWEREVENT_RESUMESUSPEND = 0x0D07; /** Service Control code which is received when the battery power is low. * Support for this event was removed from the Windows OS starting with * Vista. See SERVICE_CONTROL_CODE_POWEREVENT_POWERSTATUSCHANGE. */ public static final int SERVICE_CONTROL_CODE_POWEREVENT_BATTERYLOW = 0x0D09; /** Service Control code which is received when there is a change in the * power status of the computer, such as a switch from battery power to * A/C. The system also broadcasts this event when remaining battery * power slips below the threshold specified by the user or if the * battery power changes by a specified percentage. */ public static final int SERVICE_CONTROL_CODE_POWEREVENT_POWERSTATUSCHANGE = 0x0D0A; /** Service Control code which is received when the APM BIOS has signaled * an APM OEM event. Support for this event was removed from the Windows * OS starting with Vista. */ public static final int SERVICE_CONTROL_CODE_POWEREVENT_OEMEVENT = 0x0D0B; /** Service Control code which is received when the computer has woken up * automatically to handle an event. */ public static final int SERVICE_CONTROL_CODE_POWEREVENT_RESUMEAUTOMATIC = 0x0D12; /** Reference to the original value of System.out. */ private static PrintStream m_out; /** Reference to the original value of System.err. */ private static PrintStream m_err; /** Info level log channel */ private static WrapperPrintStream m_outInfo; /** Error level log channel */ private static WrapperPrintStream m_outError; /** Debug level log channel */ private static WrapperPrintStream m_outDebug; /** Flag to remember whether or not this is Windows. */ private static boolean m_windows = false; /** Flag to remember whether or not this is MacOSX. */ private static boolean m_macosx = false; /** Flag that will be set to true once a SecurityManager has been detected and tested. */ private static boolean m_securityManagerChecked = false; private static boolean m_disposed = false; /** The starting flag is set when the Application has been asked to start. */ private static boolean m_starting = false; /** The started flag is set when the Application has completed its startup. */ private static boolean m_started = false; private static WrapperManager m_instance = null; private static Thread m_hook = null; private static boolean m_hookTriggered = false; private static boolean m_hookRemoveFailed = false; /* Flag which records when the shutdownJVM method has completed. */ private static boolean m_shutdownJVMComplete = false; /** Map which stores shutdown locks for each thread. */ private static Map m_shutdownLockMap = new HashMap(); /** Tracks the total number of outstanding shutdown locks. */ private static int m_shutdownLocks = 0; /** Tracks the number of threads which are attempting to launch child processes. */ private static int m_runningExecs = 0; private static String[] m_args; private static int m_backendType = BACKEND_TYPE_UNKNOWN; private static boolean m_backendConnected = false; private static OutputStream m_backendOS = null; private static InputStream m_backendIS = null; private static int m_port = DEFAULT_PORT; private static int m_jvmPort; private static int m_jvmPortMin; private static int m_jvmPortMax; private static String m_wrapperPortAddress = null; private static String m_key; private static int m_soTimeout = -1; private static long m_cpuTimeout = DEFAULT_CPU_TIMEOUT; /** Tick count when the start method completed. */ private static int m_startedTicks; /** The lowest configured log level in the Wrapper's configuration. This * is set to a high value by default to disable all logging if the * Wrapper does not register its low level or is not present. */ private static int m_lowLogLevel = WRAPPER_LOG_LEVEL_NOTICE + 1; /** Flag, set when the JVM is launched that is used to remember whether * or not system signals are supposed to be ignored. */ private static boolean m_ignoreSignals = false; /** Flag which controls whether the Wrapper process is expected to close the * connection after the STARTED packet is sent. */ private static boolean m_detachStarted = false; /** Thread which processes all communications with the native code. */ private static Thread m_commRunner; private static boolean m_commRunnerStarted = false; private static Thread m_eventRunner; private static int m_eventRunnerTicks; private static Thread m_startupRunner; /** True if the system time should be used for internal timeouts. */ private static boolean m_useSystemTime; /** The threashold of how many ticks the timer can be fast before a * warning is displayed. */ private static int m_timerFastThreshold; /** The threashold of how many ticks the timer can be slow before a * warning is displayed. */ private static int m_timerSlowThreshold; /** Flag which controls whether or not the test methods are disabled. */ private static boolean m_disableTests; /** Flag which controls whether or not the WrapperListener.stop method will * be called on shutdown when the WrapperListener.start method has not * returned or returned an exit code. */ private static boolean m_listenerForceStop; /** * Bit depth of the currently running JVM. Will be 32 or 64. * A 64-bit JVM means that the system is also 64-bit, but a 32-bit JVM * can be run either on a 32 or 64-bit system. */ private static int m_jvmBits; /** An integer which stores the number of ticks since the * JVM was launched. Using an int rather than a long allows the value * to be used without requiring any synchronization. This is only * used if the m_useSystemTime flag is false. */ private static volatile int m_ticks; private static WrapperListener m_listener; private static int m_lastPingTicks; private static Socket m_backendSocket; private static boolean m_appearHung = false; private static int m_slowSeconds = 0; private static boolean m_ignoreUserLogoffs = false; private static boolean m_service = false; private static boolean m_debug = false; private static boolean m_logFinalizer = false; private static int m_jvmId = 0; /** Flag set when any thread initiates a stop or restart. */ private static boolean m_stoppingInit = false; /** Flag set when the thread that will be in charge of actually stopping has been fixed. */ private static boolean m_stopping = false; /** Thread that is in charge of stopping. */ private static Thread m_stoppingThread; /** Flag set when the the thread which is charge of stopping has completed. The Wrapper JNI code could then become invalid at any time and should no longer be trusted. */ private static boolean m_stopped = false; /** If set then this message will be sent as a STOP message as soon as we connect to the Wrapper. */ private static String m_pendingStopMessage = null; private static int m_exitCode; private static boolean m_libraryOK = false; private static byte[] m_commandBuffer = new byte[512]; private static File m_logFile = null; /** The contents of the wrapper configuration. */ private static WrapperProperties m_properties; /** List of registered WrapperEventListeners and their registered masks. */ private static List m_wrapperEventListenerMaskList = new ArrayList(); /** Array of registered WrapperEventListeners and their registered masks. * Should not be referenced directly. Access by calling * getWrapperEventListenerMasks(). */ private static WrapperEventListenerMask[] m_wrapperEventListenerMasks = null; /** Flag used to tell whether or not WrapperCoreEvents should be produced. */ private static boolean m_produceCoreEvents = false; // message resources: eventually these will be split up private static WrapperResources m_res; /** Set on startup to show whether or not a Professional edition library is being used. * Overriding this makes no difference as the underlying library also contains these checks. * Caching this value makes it possible to reduce the number of JNI calls and avoid confusing * errors on shutdown. */ private static boolean m_professionalEdition; /** Set on startup to show whether or not a Standard edition library is being used. * Overriding this makes no difference as the underlying library also contains these checks. * Caching this value makes it possible to reduce the number of JNI calls and avoid confusing * errors on shutdown. */ private static boolean m_standardEdition; /** * Returns the WrapperResources object which is used to manage all resources for * the Java Service Wrapper. * * @return the Wrapper's resouces. */ public static WrapperResources getRes() { return m_res; } /*--------------------------------------------------------------- * Class Initializer *-------------------------------------------------------------*/ /** * When the WrapperManager class is first loaded, it attempts to load the * configuration file specified using the 'wrapper.config' system property. * When the JVM is launched from the Wrapper native code, the * 'wrapper.config' and 'wrapper.key' parameters are specified. * The 'wrapper.key' parameter is a password which is used to verify that * connections are only coming from the native Wrapper which launched the * current JVM. */ static { // The wraper.jar must be given AllPermissions if a security manager // has been configured. This is not a problem if one of the standard // Wrapper helper classes is used to launch the JVM. // If however a custom WrapperListener is being implemented then this // class will most likely be loaded by code that is neither part of // the system, nor part of the Wrapper code base. To avoid having // to also give those classes AllPermissions as well, we do all of // initialization in a Privileged block. This means that the code // only requires that the wrapper.jar has been given the required // permissions. AccessController.doPrivileged( new PrivilegedAction() { public Object run() { privilegedClassInit(); return null; } } ); } /** * Logs information about the package of the specified class. * * @param clazz Class to log. */ private static void logPackageInfo( Class clazz ) { if ( m_debug ) { Package pkg = WrapperManager.class.getPackage(); if ( pkg == null ) { m_outDebug.println( getRes().getString( "{0} package not found.", clazz.getName() ) ); } else { m_outDebug.println( getRes().getString( "{0} package information:", clazz.getName() ) ); m_outDebug.println( getRes().getString( " Implementation Title: {0}", pkg.getImplementationTitle() ) ); m_outDebug.println( getRes().getString( " Implementation Vendor: {0}", pkg.getImplementationVendor() ) ); m_outDebug.println( getRes().getString( " Implementation Version: {0}", pkg.getImplementationVersion() ) ); m_outDebug.println( getRes().getString( " Is Sealed?: {0}", pkg.isSealed() ? getRes().getString( "True" ) : getRes().getString( "False" ) ) ); } ProtectionDomain proDom = clazz.getProtectionDomain(); m_outDebug.println( getRes().getString( "{0} protection domain:", clazz.getName() ) ); CodeSource codeSource = proDom.getCodeSource(); URL jarLocation = codeSource.getLocation(); m_outDebug.println( getRes().getString( " Location: {0}", jarLocation ) ); // Try reading in the full jar so we can calculate its size and MD5 hash. try { InputStream is = jarLocation.openStream(); try { int jarSize = 0; MessageDigest md = MessageDigest.getInstance( "MD5" ); int data; while ( ( data = is.read() ) >= 0 ) { jarSize++; md.update( (byte)( data & 0xff ) ); } m_outDebug.println( getRes().getString( " Size: {0}", new Integer( jarSize ) ) ); byte[] bytes = md.digest(); StringBuffer sb = new StringBuffer(); for ( int i = 0; i < bytes.length; i++ ) { String val = Integer.toString( bytes[i] & 0xff, 16 ).toLowerCase(); if ( val.length() == 1 ) { sb.append( "0" ); } sb.append( val ); } m_outDebug.println( getRes().getString( " MD5: {0}" , sb ) ); } finally { is.close(); } } catch ( NoSuchAlgorithmException e ) { m_outDebug.println( getRes().getString( " Unable to calculate MD5: {0}", e ) ); } catch ( IOException e ) { m_outDebug.println( getRes().getString( " Unable to access location: {0}", e ) ); } } } /** * The body of the static initializer is moved into a seperate method so * it can be run as a PrivilegedAction. */ private static void privilegedClassInit() { // Store references to the original System.out and System.err // PrintStreams. The WrapperManager will always output to the // original streams so its output will always end up in the // wrapper.log file even if the end user code redirects the // output to another log file. // This is also important to be protect the Wrapper's functionality // from the case where the user PrintStream enters a deadlock state. m_out = System.out; m_err = System.err; // Set up some log channels m_outInfo = new WrapperPrintStream( m_out, "WrapperManager: " ); m_outError = new WrapperPrintStream( m_out, "WrapperManager Error: " ); m_outDebug = new WrapperPrintStream( m_out, "WrapperManager Debug: " ); // Always create an empty properties object in case we are not running // in the Wrapper or the properties are never sent. m_properties = new WrapperProperties(); m_properties.lock(); // Create a dummy resources file so initial localization will work until the native library is loaded. m_res = new WrapperResources(); // This must be done before attempting to access any System Properties // as that could cause a SecurityException if it is too strict. checkSecurityManager(); // Check for the debug flag m_debug = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.debug", false ); if ( m_debug ) { // This message is logged when localization is not yet initialized. m_outDebug.println( "WrapperManager class initialized by thread: " + Thread.currentThread().getName() + " Using classloader: " + WrapperManager.class.getClassLoader().toString() ); } // The copyright banner was moved into the wrapper binary. In order to // aid in the debugging of user integrations, some kind of a known message // needs to be displayed on startup so it is obvious whether or not the // WrapperManager class is being initialized. // This message is logged when localization is not yet initialized. m_outInfo.println( "Initializing..." ); // We need to get the key before the version can be verified. m_key = System.getProperty( "wrapper.key" ); // Make sure that the version of the Wrapper is correct. verifyWrapperVersion(); // Store the log finalizer flag. m_logFinalizer = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.logFinalizers", false ); // Check for the jvmID m_jvmId = WrapperSystemPropertyUtil.getIntProperty( "wrapper.jvmid", 1 ); if ( m_debug ) { // This message is logged when localization is not yet initialized. m_outDebug.println( "JVM #" + m_jvmId ); } // Decide whether this is a 32 or 64 bit version of Java. m_jvmBits = WrapperSystemPropertyUtil.getIntProperty( "sun.arch.data.model", -1 ); if ( m_jvmBits == -1 ) { m_jvmBits = WrapperSystemPropertyUtil.getIntProperty( "com.ibm.vm.bitmode", -1 ); } if ( m_debug ) { if ( m_jvmBits > 0 ) { // This message is logged when localization is not yet initialized. m_outDebug.println( "Running a " + m_jvmBits + "-bit JVM." ); } else { // This message is logged when localization is not yet initialized. m_outDebug.println( "The bit depth of this JVM could not be determined." ); } } // Log information about the Wrapper's package. logPackageInfo( WrapperManager.class ); // Get the detachStarted flag. m_detachStarted = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.detachStarted", false ); // Initialize the timerTicks to a very high value. This means that we will // always encounter the first rollover (200 * WRAPPER_MS / 1000) seconds // after the Wrapper the starts, which means the rollover will be well // tested. m_ticks = Integer.MAX_VALUE - 200; m_useSystemTime = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.use_system_time", false ); m_timerFastThreshold = WrapperSystemPropertyUtil.getIntProperty( "wrapper.timer_fast_threshold", TIMER_FAST_THRESHOLD ) * 1000 / TICK_MS; m_timerSlowThreshold = WrapperSystemPropertyUtil.getIntProperty( "wrapper.timer_slow_threshold", TIMER_SLOW_THRESHOLD ) * 1000 / TICK_MS; // Check to see if we should disable test methods m_disableTests = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.disable_tests", false ); // Check to see if we should register a shutdown hook boolean disableShutdownHook = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.disable_shutdown_hook", false ); // Check to see if the listener stop method should always be called. m_listenerForceStop = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.listener.force_stop", false ); // Make it possible for a user to set the SO_TIMEOUT of the backend. Mainly for testing. m_soTimeout = WrapperSystemPropertyUtil.getIntProperty( "wrapper.backend.so_timeout", -1 ) * 1000; // If the shutdown hook is not disabled, then register it. if ( !disableShutdownHook ) { if ( m_debug ) { // This message is logged when localization is not yet initialized. m_outDebug.println( "Registering shutdown hook" ); } m_hook = new Thread( "Wrapper-Shutdown-Hook" ) { /** * Run the shutdown hook. (Triggered by the JVM when it is about to shutdown) */ public void run() { // Stop the Wrapper cleanly. m_hookTriggered = true; if ( m_debug ) { m_outDebug.println( getRes().getString( "ShutdownHook started" ) ); } // Let the startup thread die since the shutdown hook is running. m_startupRunner = null; // If we are not already stopping, then do so. WrapperManager.stop( 0 ); if ( m_debug ) { m_outDebug.println( getRes().getString( "ShutdownHook complete" ) ); } // Really all done. if ( m_debug ) { m_outDebug.println( getRes().getString( "WrapperManger stopped due to {0}", getRes().getString( "Shutdown Hook" ) ) ); } m_stopped = true; } }; // Register the shutdown hook. Runtime.getRuntime().addShutdownHook( m_hook ); } // Initialize connection values. m_backendType = BACKEND_TYPE_UNKNOWN; m_port = 0; m_jvmPort = 0; m_jvmPortMin = 0; m_jvmPortMax = 0; // A key is required for the wrapper to work correctly. If it is not // present, then assume that we are not being controlled by the native // wrapper. if ( m_key == null ) { if ( m_debug ) { // This message is logged when localization is not yet initialized. m_outDebug.println( "Not using wrapper. (key not specified)" ); } // The wrapper will not be used, so other values will not be used. m_service = false; m_cpuTimeout = 31557600000L; // One Year. Effectively never. } else { if ( m_debug ) { m_outDebug.println( getRes().getString( "Using wrapper" ) ); } if ( WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.disable_console_input", false ) ) { // Replace the System.in stream with one of our own to disable it. System.setIn( new WrapperInputStream() ); } // Decide what the backend connection type is String backendType = WrapperSystemPropertyUtil.getStringProperty( "wrapper.backend", "SOCKET" ); if ( backendType.equalsIgnoreCase( "PIPE" ) ) { // Pipe based communication m_backendType = BACKEND_TYPE_PIPE; } else { // Socket based communication if (backendType.equalsIgnoreCase( "SOCKET" ) ) { m_backendType = BACKEND_TYPE_SOCKET_V4; } else{ m_backendType = BACKEND_TYPE_SOCKET_V6; } // An address may not have been specified. if ( ( m_wrapperPortAddress = System.getProperty( "wrapper.port.address" ) ) == null ) { /* Use the default loopback */ if (m_backendType == BACKEND_TYPE_SOCKET_V4) { m_wrapperPortAddress = "127.0.0.1"; } else { m_wrapperPortAddress = "::1"; } } String sPort; if ( ( sPort = System.getProperty( "wrapper.port" ) ) == null ) { // This message is logged when localization is not yet initialized. String msg = "The 'wrapper.port' system property was not set."; m_outError.println( msg ); throw new ExceptionInInitializerError( msg ); } try { m_port = Integer.parseInt( sPort ); } catch ( NumberFormatException e ) { // This message is logged when localization is not yet initialized. String msg = "'" + sPort + "' is not a valid value for 'wrapper.port'."; m_outError.println( msg ); throw new ExceptionInInitializerError( msg ); } m_jvmPort = WrapperSystemPropertyUtil.getIntProperty( "wrapper.jvm.port", -1 ); m_jvmPortMin = WrapperSystemPropertyUtil.getIntProperty( "wrapper.jvm.port.min", 31000 ); m_jvmPortMax = WrapperSystemPropertyUtil.getIntProperty( "wrapper.jvm.port.max", 31999 ); } // Check for the ignore signals flag m_ignoreSignals = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.ignore_signals", false ); // If this is being run as a headless server, then a flag would have been set m_service = WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.service", false ); // Get the cpuTimeout String sCPUTimeout = System.getProperty( "wrapper.cpu.timeout" ); if ( sCPUTimeout == null ) { m_cpuTimeout = DEFAULT_CPU_TIMEOUT; } else { try { m_cpuTimeout = Integer.parseInt( sCPUTimeout ) * 1000L; } catch ( NumberFormatException e ) { // This message is logged when localization is not yet initialized. String msg = "'" + sCPUTimeout + "' is not a valid value for 'wrapper.cpu.timeout'."; m_outError.println( msg ); throw new ExceptionInInitializerError( msg ); } } } // Register the MBeans if configured to do so. if ( WrapperSystemPropertyUtil.getBooleanProperty( WrapperManager.class.getName() + ".mbean", true ) ) { registerMBean( new org.tanukisoftware.wrapper.jmx.WrapperManager(), "org.tanukisoftware.wrapper:type=WrapperManager" ); } if ( WrapperSystemPropertyUtil.getBooleanProperty( WrapperManager.class.getName() + ".mbean.testing", false ) ) { registerMBean( new org.tanukisoftware.wrapper.jmx.WrapperManagerTesting(), "org.tanukisoftware.wrapper:type=WrapperManagerTesting" ); } // Initialize the native code to trap system signals initializeNativeLibrary(); if ( isNativeLibraryOk() ) { // Make sure that the native library's version is correct. verifyNativeLibraryVersion(); // Get the PID of the current JVM from the native library. Be careful as the method // will not exist if the library is old. try { System.setProperty( "wrapper.java.pid", Integer.toString( nativeGetJavaPID() ) ); } catch ( Throwable e ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Call to nativeGetJavaPID() failed: {0}", e ) ); } } } // Start a thread which looks for control events sent to the // process. The thread is also used to keep track of whether // the VM has been getting CPU to avoid invalid timeouts and // to maintain the number of ticks since the JVM was launched. m_eventRunnerTicks = getTicks(); m_eventRunner = new Thread( "Wrapper-Control-Event-Monitor" ) { public void run() { if ( m_debug ) { m_outDebug.println( getRes().getString( "Control event monitor thread started." ) ); } try { WrapperTickEventImpl tickEvent = new WrapperTickEventImpl(); int lastTickOffset = 0; boolean first = true; boolean stoppingLogged = false; // This loop should not exit until the WrapperManager is completely stopped. while ( !m_stopped ) { int offsetDiff; if ( !m_useSystemTime ) { // Get the tick count based on the system time. int sysTicks = getSystemTicks(); // Increment the tick counter by 1. This loop takes just slightly // more than the length of a "tick" but it is a good enough // approximation for our purposes. The accuracy of the tick length // falls sharply when the system is under heavly load, but this // has the desired effect as the Wrapper is also much less likely // to encounter false timeouts due to the heavy load. // The ticks field is volatile and a single integer, so it is not // necessary to synchronize this. // When the ticks count reaches the upper limit of the int range, // it is ok to just let it overflow and wrap. m_ticks++; // Calculate the offset between the two tick counts. // This will always work due to overflow. int tickOffset = sysTicks - m_ticks; // The number we really want is the difference between this tickOffset // and the previous one. offsetDiff = tickOffset - lastTickOffset; if ( first ) { first = false; } else { if ( offsetDiff > m_timerSlowThreshold ) { m_outInfo.println( getRes().getString( "The timer fell behind the system clock by {0} ms." , new Integer( offsetDiff * TICK_MS ) ) ); } else if ( offsetDiff < - m_timerFastThreshold ) { m_outInfo.println( getRes().getString( "The system clock fell behind the timer by {0} ms." , new Integer( -1 * offsetDiff * TICK_MS ) ) ); } } // Store this tick offset for the net time through the loop. lastTickOffset = tickOffset; } else { offsetDiff = 0; } //m_outInfo.println( " UNIX Time: " // + Long.toHexString( System.currentTimeMillis() ) // + ", ticks=" + Integer.toHexString( getTicks() ) + ", sysTicks=" // + Integer.toHexString( getSystemTicks() ) ); // Attempt to detect whether or not we are being starved of CPU. // This will only have any effect if the m_useSystemTime flag is // set. // The tick timer will always result in an age of exactly one // because it is incremented each time through this loop. int nowTicks = getTicks(); long age = getTickAge( m_eventRunnerTicks, nowTicks ); if ( ( m_cpuTimeout > 0 ) && ( age > m_cpuTimeout ) ) { m_outInfo.println( getRes().getString( "JVM Process has not received any CPU time for {0} seconds. Extending timeouts." , new Long( age / 1000 ) ) ); // Make sure that we don't get any ping timeouts in this event m_lastPingTicks = nowTicks; } m_eventRunnerTicks = nowTicks; // If there are any listeners interrested in core events then fire // off a tick event. if ( m_produceCoreEvents ) { tickEvent.m_ticks = nowTicks; tickEvent.m_tickOffset = offsetDiff; fireWrapperEvent( tickEvent ); } if ( isNativeLibraryOk() ) { // To avoid the JVM shutting down while we are in the middle of a JNI call, if ( !isShuttingDown() ) { // Look for control events in the wrapper library. // There may be more than one. int event = 0; do { event = WrapperManager.nativeGetControlEvent(); if ( event != 0 ) { WrapperManager.controlEvent( event ); } } while ( event != 0 ); } else if ( !stoppingLogged ) { stoppingLogged = true; if ( m_debug ) { m_outDebug.println( getRes().getString( "Stopped checking for control events." ) ); } } } // Wait before checking for another control event. try { Thread.sleep( TICK_MS ); } catch ( InterruptedException e ) { } } } finally { if ( m_debug ) { m_outDebug.println( getRes().getString( "Control event monitor thread stopped." ) ); } } } }; m_eventRunner.setDaemon( true ); m_eventRunner.start(); // Resolve the system thread count based on the Java Version String fullVersion = System.getProperty( "java.fullversion" ); String vendor = System.getProperty( "java.vm.vendor", "" ); String os = System.getProperty( "os.name", "" ).toLowerCase(); if ( fullVersion == null ) { fullVersion = System.getProperty( "java.runtime.version" ) + " " + System.getProperty( "java.vm.name" ); } if ( m_debug ) { // Display more JVM info right after the call initialization of the // library. m_outDebug.println( getRes().getString( "Java Version : {0}", fullVersion ) ); m_outDebug.println( getRes().getString( "Java VM Vendor : {0}", vendor ) ); m_outDebug.println( getRes().getString( "OS Name : {0}", System.getProperty( "os.name", "" ) ) ); m_outDebug.println( getRes().getString( "OS Arch : {0}", System.getProperty( "os.arch", "" ) ) ); m_outDebug.println(); } // This thread will most likely be thread which launches the JVM. // Once this method returns however, the main thread will likely // quit. There will be a slight delay before the Wrapper binary // has a change to send a command to start the application. // During this lag, the JVM may not have any non-daemon threads // running and would exit. To keep it from doing so, start a // simple non-daemon thread which will run until the // WrapperListener.start() method returns or the Wrapper's // shutdown thread has started. m_startupRunner = new Thread( "Wrapper-Startup-Runner" ) { public void run() { // Make sure the rest of this thread does not fall behind the application. Thread.currentThread().setPriority( Thread.MAX_PRIORITY ); if ( m_debug ) { m_outDebug.println( getRes().getString( "Startup runner thread started." ) ); } try { while ( m_startupRunner != null ) { try { Thread.sleep( 100 ); } catch ( InterruptedException e ) { // Ignore. } } } finally { if ( m_debug ) { m_outDebug.println( getRes().getString( "Startup runner thread stopped." ) ); } } } }; // This thread must not be a daemon thread. m_startupRunner.setDaemon( false ); m_startupRunner.start(); // Create the singleton m_instance = new WrapperManager(); } /*--------------------------------------------------------------- * Finalizers *-------------------------------------------------------------*/ protected void finalize() throws Throwable { try { // This should only happen if the class gets unloaded. if ( isLoggingFinalizers() ) { System.out.println( "WrapperManager.finalize" ); } } finally { super.finalize(); } } /*--------------------------------------------------------------- * Native Methods *-------------------------------------------------------------*/ private static native void nativeInit( boolean debug ); private static native String nativeGetLibraryVersion(); private static native int nativeGetJavaPID(); private static native boolean nativeIsProfessionalEdition(); private static native boolean nativeIsStandardEdition(); private static native int nativeGetControlEvent(); private static native int nativeRedirectPipes(); private static native void nativeRequestThreadDump(); private static native void accessViolationInner(); // Should start with native, but need to preserve for compatibility. private static native void nativeSetConsoleTitle( String titleBytes ); private static native WrapperUser nativeGetUser( boolean groups ); private static native WrapperUser nativeGetInteractiveUser( boolean groups ); private static native WrapperWin32Service[] nativeListServices(); private static native WrapperWin32Service nativeSendServiceControlCode( String serviceName, int controlCode ); private static native WrapperProcess nativeExec( String[] cmdArray, String cmdLine, WrapperProcessConfig config, boolean allowCWDOnSpawn ); private static native String nativeWrapperGetEnv( String val ) throws NullPointerException; private static native WrapperResources nativeLoadWrapperResources(String domain, String folder, boolean makeActive); private static native boolean nativeCheckDeadLocks(); /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns a tick count calculated from the system clock. */ private static int getSystemTicks() { // Calculate a tick count using the current system time. The // conversion from a long in ms, to an int in TICK_MS increments // will result in data loss, but the loss of bits and resulting // overflow is expected and Ok. return (int)( System.currentTimeMillis() / TICK_MS ); } /** * Returns the number of ticks since the JVM was launched. This * count is not good enough to be used where accuracy is required but * it allows us to implement timeouts in environments where the system * time is modified while the JVM is running. *

* An int is used rather than a long so the counter can be implemented * without requiring any synchronization. At the tick resolution, the * tick counter will overflow and wrap (every 6.8 years for 100ms ticks). * This behavior is expected. The getTickAge method should be used * in cases where the difference between two ticks is required. * * Returns the tick count. */ private static int getTicks() { if ( m_useSystemTime ) { return getSystemTicks(); } else { return m_ticks; } } /** * Returns the number of milliseconds that have elapsed between the * start and end counters. This method assumes that both tick counts * were obtained by calling getTicks(). This method will correctly * handle cases where the tick counter has overflowed and reset. * * @param start A base tick count. * @param end An end tick count. * * @return The number of milliseconds that are represented by the * difference between the two specified tick counts. */ private static long getTickAge( int start, int end ) { // Important to cast the first value so that negative values are correctly // cast to negative long values. return (long)( end - start ) * TICK_MS; } /** * Attempts to load the a native library file. * * @param name Name of the library to load. * @param file Name of the actual library file. * * @return null if the library was successfully loaded, an error message * otherwise. */ private static String loadNativeLibrary( String name, String file ) { try { System.loadLibrary( name ); if ( m_debug ) { m_outDebug.println( getRes().getString( " Attempt to load native library with name: {0} Result: {1}" , file, getRes().getString( "Success!" ) ) ); } return null; } catch ( UnsatisfiedLinkError e ) { if ( m_debug ) { m_outDebug.println( getRes().getString( " Attempt to load native library with name: {0} Result: {1}" , file, e.getMessage() ) ); } String error = e.getMessage(); if ( error == null ) { error = e.toString(); } return error; } catch ( Throwable e ) { if ( m_debug ) { m_outDebug.println( getRes().getString( " Attempt to load native library with name: {0} Result: {1}" , file, e.getMessage() ) ); } String error = e.toString(); return error; } } /** * Java 1.5 and above supports the ability to register the WrapperManager * MBean internally. */ private static void registerMBean( Object mbean, String name ) { Class classManagementFactory; Class classMBeanServer; Class classObjectName; try { classManagementFactory = Class.forName( "java.lang.management.ManagementFactory" ); classMBeanServer = Class.forName( "javax.management.MBeanServer" ); classObjectName = Class.forName( "javax.management.ObjectName" ); } catch ( ClassNotFoundException e ) { if ( m_debug ) { m_outDebug.println(getRes().getString( "Registering MBeans not supported by current JVM: {0}" , name ) ); } return; } try { // This code uses reflection so it combiles on older JVMs. // The original code is as follows: // javax.management.MBeanServer mbs = // java.lang.management.ManagementFactory.getPlatformMBeanServer(); // javax.management.ObjectName oName = new javax.management.ObjectName( name ); // mbs.registerMBean( mbean, oName ); // The version of the above code using reflection follows. Method methodGetPlatformMBeanServer = classManagementFactory.getMethod( "getPlatformMBeanServer", (Class[])null ); Constructor constructorObjectName = classObjectName.getConstructor( new Class[] {String.class} ); Method methodRegisterMBean = classMBeanServer.getMethod( "registerMBean", new Class[] {Object.class, classObjectName} ); Object mbs = methodGetPlatformMBeanServer.invoke( (Object)null, (Object[])null ); Object oName = constructorObjectName.newInstance( new Object[] {name} ); methodRegisterMBean.invoke( mbs, new Object[] {mbean, oName} ); if ( m_debug ) { m_outDebug.println( getRes().getString( "Registered MBean with Platform MBean Server: {0}", name ) ); } } catch ( Throwable t ) { if ( t instanceof ClassNotFoundException ) { m_outError.println( "Using MBean requires at least a JVM version 1.5." ); } m_outError.println( "Unable to register the " + name + " MBean." ); t.printStackTrace( m_outError ); } } /** * Searches for a file on a path. * * @param file File to look for. * @param path Path to be searched. * * @return Reference to thr file object if found, otherwise null. */ private static File locateFileOnPath( String file, String path ) { // A library path exists but the library was not found on it. String pathSep = System.getProperty( "path.separator" ); // Search for the file on the library path to verify that it does not // exist, it could be some other problem StringTokenizer st = new StringTokenizer( path, pathSep ); while( st.hasMoreTokens() ) { File libFile = new File( new File( st.nextToken() ), file ); if ( libFile.exists() ) { return libFile; } } return null; } /** * Generates a detailed native library base name which is made up of the * base name, the os name, architecture, and the bits of the current JVM, * not the platform. * * @return A detailed native library base name. */ private static String generateDetailedNativeLibraryBaseName( String baseName, int jvmBits ) { // Generate an os name. Most names are used as is, but some are modified. String os = System.getProperty( "os.name", "" ).toLowerCase(); if ( os.startsWith( "windows" ) ) { os = "windows"; m_windows = true; } else if ( os.equals( "sunos" ) ) { os = "solaris"; } else if ( os.equals( "hp-ux" ) || os.equals( "hp-ux64" ) ) { os = "hpux"; } else if ( os.equals( "mac os x" ) ) { os = "macosx"; m_macosx = true; } else if ( os.equals( "unix_sv" ) ) { os = "unixware"; } else if ( os.equals( "os/400" ) ) { os = "os400"; } else if ( os.equals( "z/os" ) ) { os = "zos"; } // Generate an architecture name. String arch; if ( m_macosx ) { arch = "universal"; } else { arch = System.getProperty( "os.arch", "" ).toLowerCase(); if ( arch.equals( "amd64" ) || arch.equals( "athlon" ) || arch.equals( "x86_64" ) || arch.equals( "i686" ) || arch.equals( "i586" ) || arch.equals( "i486" ) || arch.equals( "i386" ) ) { arch = "x86"; } else if ( arch.startsWith( "ia32" ) || arch.startsWith( "ia64" ) ) { arch = "ia"; } else if ( arch.startsWith( "sparc" ) ) { arch = "sparc"; } else if ( arch.equals( "power" ) || arch.equals( "powerpc" ) || arch.equals( "ppc64" ) ) { arch = "ppc"; } else if ( arch.startsWith( "pa_risc" ) || arch.startsWith( "pa-risc" ) ) { arch = "parisc"; } else if ( arch.startsWith( "arm" ) ) { arch = System.getProperty( "wrapper.arch" ); } else if ( arch.equals( "s390" ) || arch.equals( "s390x" ) ) { arch = "390"; } } return baseName + "-" + os + "-" + arch + "-" + jvmBits; } /** * Searches for and then loads the native library. This method will attempt * locate the wrapper library using one of the following 3 naming */ private static void initializeNativeLibrary() { // Look for the base name of the library. String baseName = System.getProperty( "wrapper.native_library" ); if ( baseName == null ) { // This should only happen if an old version of the Wrapper binary is being used. // This message is logged when localization is not yet initialized. m_outInfo.println( "WARNING - The wrapper.native_library system property was not" ); m_outInfo.println( " set. Using the default value, 'wrapper'." ); baseName = "wrapper"; } String[] detailedNames = new String[4]; if ( m_jvmBits > 0 ) { detailedNames[0] = generateDetailedNativeLibraryBaseName( baseName, m_jvmBits ); } else { detailedNames[0] = generateDetailedNativeLibraryBaseName( baseName, 32 ); detailedNames[1] = generateDetailedNativeLibraryBaseName( baseName, 64 ); } // Construct brief and detailed native library file names. String file = System.mapLibraryName( baseName ); String[] detailedFiles = new String[detailedNames.length]; for ( int i = 0; i < detailedNames.length; i++ ) { if ( detailedNames[i] != null ) { detailedFiles[i] = System.mapLibraryName( detailedNames[i] ); } } String[] detailedErrors = new String[detailedNames.length]; String baseError = null; // Try loading the native library using the detailed name first. If that fails, use // the brief name. if ( m_debug ) { // This message is logged when localization is not yet initialized. m_outDebug.println( "Load native library. There are multiple possible file names and the first to be found will be used. Errors loading non-existing files is normal and is only a problem if they all fail." ); } m_libraryOK = false; for ( int i = 0; i < detailedNames.length; i++ ) { if ( detailedNames[i] != null ) { detailedErrors[i] = loadNativeLibrary( detailedNames[i], detailedFiles[i] ); if ( detailedErrors[i] == null ) { m_libraryOK = true; break; } } } if ( ( !m_libraryOK ) && ( ( baseError = loadNativeLibrary( baseName, file ) ) == null ) ) { m_libraryOK = true; } if ( m_libraryOK ) { if ( m_debug ) { // This message is logged when localization is not yet initialized. m_outDebug.println( " Successfully loaded native library." ); } // Cache the values of the professional and standard edition flags. try { m_professionalEdition = nativeIsProfessionalEdition(); } catch ( Throwable e ) { if ( m_debug ) { // This message is logged when localization is not yet initialized. m_outDebug.println( "Call to nativeIsProfessionalEdition() failed: " + e ); } m_professionalEdition = false; } try { m_standardEdition = nativeIsStandardEdition(); } catch ( Throwable e ) { if ( m_debug ) { // This message is logged when localization is not yet initialized. m_outDebug.println( "Call to nativeIsStandardEdition() failed: " + e ); } m_standardEdition = false; } // Try reloading the resources once the library is initialized so we get actual localized content. // We do this before trying to initialize the native library intentionally so any messages will be // localized correctly. This one call is designed to handle this state. m_res = loadWrapperResourcesInner( System.getProperty( "wrapper.lang.domain") + "jni", WrapperSystemPropertyUtil.getStringProperty( "wrapper.lang.folder", "../lang" ), true ); if ( m_debug ) { m_outDebug.println( getRes().getString( "Loaded localized resources." ) ); } // The library was loaded correctly, so initialize it. if ( m_debug ) { m_outDebug.println( getRes().getString( "Calling native initialization method." ) ); } nativeInit( m_debug ); if ( m_stoppingInit ) { // Certain checks in the nativeInit call can result in the JVM starting to shutdown. // Avoid further JNI related messages that would be confusing. m_libraryOK = false; } } else { // The library could not be loaded, so we want to give the user a useful // clue as to why not. String libPath = System.getProperty( "java.library.path" ); m_outInfo.println(); if ( libPath.equals( "" ) ) { // No library path // This message is logged when localization is unavailable. m_outInfo.println( "WARNING - Unable to load the Wrapper's native library because the" ); m_outInfo.println( " java.library.path was set to ''. Please see the" ); m_outInfo.println( " documentation for the wrapper.java.library.path" ); m_outInfo.println( " configuration property." ); } else { // Attempt to locate the actual files on the path. String error = null; File libFile = null; for ( int i = 0; i < detailedNames.length; i++ ) { if ( detailedFiles[i] != null ) { libFile = locateFileOnPath( detailedFiles[i], libPath ); if ( libFile != null ) { error = detailedErrors[i]; break; } } } if ( libFile == null ) { libFile = locateFileOnPath( file, libPath ); if ( libFile != null ) { error = baseError; } } if ( libFile == null ) { // The library could not be located on the library path. // This message is logged when localization is unavailable. m_outInfo.println( "WARNING - Unable to load the Wrapper's native library because none of the" ); m_outInfo.println( " following files:" ); for ( int i = 0; i < detailedNames.length; i++ ) { if ( detailedFiles[i] != null ) { m_outInfo.println( " " + detailedFiles[i] ); } } m_outInfo.println( " " + file ); m_outInfo.println( " could be located on the following java.library.path:" ); String pathSep = System.getProperty( "path.separator" ); StringTokenizer st = new StringTokenizer( libPath, pathSep ); while ( st.hasMoreTokens() ) { File pathElement = new File( st.nextToken() ); m_outInfo.println( " " + pathElement.getAbsolutePath() ); } m_outInfo.println( " Please see the documentation for the wrapper.java.library.path" ); m_outInfo.println( " configuration property." ); } else { // The library file was found but could not be loaded for some reason. // This message is logged when localization is unavailable. m_outInfo.println( "WARNING - Unable to load the Wrapper's native library '" + libFile.getName() + "'." ); m_outInfo.println( " The file is located on the path at the following location but" ); m_outInfo.println( " could not be loaded:" ); m_outInfo.println( " " + libFile.getAbsolutePath() ); m_outInfo.println( " Please verify that the file is both readable and executable by the" ); m_outInfo.println( " current user and that the file has not been corrupted in any way." ); m_outInfo.println( " One common cause of this problem is running a 32-bit version" ); m_outInfo.println( " of the Wrapper with a 64-bit version of Java, or vica versa." ); if ( m_jvmBits > 0 ) { m_outInfo.println( " This is a " + m_jvmBits + "-bit JVM." ); } else { m_outInfo.println( " The bit depth of this JVM could not be determined." ); } m_outInfo.println( " Reported cause:" ); m_outInfo.println( " " + error ); } } // This message is logged when localization is unavailable. m_outInfo.println( " System signals will not be handled correctly." ); m_outInfo.println(); } } /** * Compares the version of the wrapper which launched this JVM with that of * the jar. If they differ then a Warning message will be displayed. The * Wrapper application will still be allowed to start. */ private static void verifyWrapperVersion() { // If we are not being controlled by the wrapper then return. if ( !WrapperManager.isControlledByNativeWrapper() ) { return; } // Lookup the version from the wrapper. It should have been set as a property // when the JVM was launched. String wrapperVersion = System.getProperty( "wrapper.version" ); if ( wrapperVersion == null ) { wrapperVersion = getRes().getString( "unknown" ); } if ( wrapperVersion.endsWith( "-pro" ) ) { wrapperVersion = wrapperVersion.substring( 0, wrapperVersion.length() - 4 ); } else if ( wrapperVersion.endsWith( "-st" ) ) { wrapperVersion = wrapperVersion.substring( 0, wrapperVersion.length() - 3 ); } if ( !WrapperInfo.getVersion().equals( wrapperVersion ) ) { // This message is logged when localization is not yet initialized. m_outInfo.println( "WARNING - The Wrapper jar file currently in use is version \"" + WrapperInfo.getVersion() + "\"" ); m_outInfo.println( " while the version of the Wrapper which launched this JVM is" ); m_outInfo.println( " \"" + wrapperVersion + "\"." ); m_outInfo.println( " The Wrapper may appear to work correctly but some features may" ); m_outInfo.println( " not function correctly. This configuration has not been tested" ); m_outInfo.println( " and is not supported." ); m_outInfo.println(); } } /** * Compares the version of the native library with that of this jar. If * they differ then a Warning message will be displayed. The Wrapper * application will still be allowed to start. */ private static void verifyNativeLibraryVersion() { // Request the version from the native library. Be careful as the method // will not exist if the library is old. String jniVersion; try { jniVersion = nativeGetLibraryVersion(); } catch ( Throwable e ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Call to nativeGetLibraryVersion() failed: {0}", e ) ); } jniVersion = getRes().getString( "unknown" ); } String wrapperVersion = System.getProperty( "wrapper.version" ); if ( wrapperVersion == null ) { wrapperVersion = getRes().getString( "unknown" ); } if ( !wrapperVersion.equals( jniVersion ) ) { m_outInfo.println( getRes().getString( "WARNING - The version of the Wrapper which launched this JVM is\n \"{0}\" while the version of the native library\n is \"{1}\".", wrapperVersion, jniVersion ) ); m_outInfo.println(getRes().getString( " The Wrapper may appear to work correctly but some features may\n not function correctly. This configuration has not been tested\n and is not supported." ) ); m_outInfo.println(); } } /** * Checks to make sure that the configured temp directory is writable. Failures are only logged * to debug output. */ private static void checkTmpDir() { File tmpDir = new File( System.getProperty( "java.io.tmpdir" ) ); if ( m_debug ) { m_outDebug.println( getRes().getString( "Java temporary directory: {0}", tmpDir ) ); } boolean tmpDirCheck = getProperties().getProperty( "wrapper.java.tmpdir.check", "TRUE").equalsIgnoreCase( "TRUE" ); if ( !tmpDirCheck ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Validation of temporary directory disabled." ) ); } return; } boolean tmpDirRequired = getProperties().getProperty( "wrapper.java.tmpdir.required", "FALSE" ).equalsIgnoreCase( "TRUE" ); boolean tmpDirWarnSilently = getProperties().getProperty( "wrapper.java.tmpdir.warn_silently", "TRUE" ).equalsIgnoreCase( "TRUE" ); Exception ex = null; try { tmpDir = tmpDir.getCanonicalFile(); File tempFile = new File( tmpDir, "wrapper-" + System.currentTimeMillis() + "-" + getJavaPID() ); if ( tempFile.createNewFile() ) { if ( !tempFile.delete() ) { m_outError.println( "Unable to delete temporary file: " + tempFile ); } } else { if ( m_debug ) { m_outDebug.println( "Unable to create temporary file: " + tempFile ); } } } catch ( IOException e ) { ex = e; } catch ( SecurityException e ) { ex = e; } if ( ex != null ) { if ( tmpDirRequired ) { m_outError.println( getRes().getString( "Unable to write to the configured Java temporary directory: {0} : {1}", tmpDir, ex.toString() ) ); m_outError.println( getRes().getString( "Shutting down." ) ); System.exit( 1 ); } else { if ( tmpDirWarnSilently ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Unable to write to the configured Java temporary directory: {0} : {1}", tmpDir, ex.toString() ) ); } } else { m_outInfo.println( getRes().getString( "Unable to write to the configured Java temporary directory: {0} : {1}", tmpDir,ex.toString() ) ); } if ( m_debug ) { m_outDebug.println( getRes().getString( " The lack of a temp directory could lead to problems with features that store temporary data, including remote jar class loading." ) ); m_outDebug.println( getRes().getString( " The Java temporary directory can be redefined with the java.io.tmpdir system property." ) ); } } } } /** * Loads a WrapperResources based on the current locale of the JVM. * * @param domain Domain of the resource. * @param folder Location of the resource. * * @return The requested resource. */ private static WrapperResources loadWrapperResourcesInner( String domain, String folder, boolean makeActive ) { if ( WrapperManager.isStandardEdition() && isNativeLibraryOk() ) { if ( folder == null ) { folder = WrapperSystemPropertyUtil.getStringProperty( "wrapper.lang.folder", "../lang" ); } return nativeLoadWrapperResources( domain, folder, makeActive ); } else { return new WrapperResources(); } } /** * Loads a WrapperResources based on the current locale of the JVM. * * @param domain Domain of the resource. * @param folder Location of the resource. * * @return The requested resource. */ public static WrapperResources loadWrapperResources( String domain, String folder ) { return loadWrapperResourcesInner( domain, folder, false ); } /** * Obtain the current version of Wrapper. * * @return The version of the Wrapper. */ public static String getVersion() { return WrapperInfo.getVersion(); } /** * Obtain the build time of Wrapper. * * @return The time that the Wrapper was built. */ public static String getBuildTime() { return WrapperInfo.getBuildTime(); } /** * Returns the Id of the current JVM. JVM Ids increment from 1 each time * the wrapper restarts a new one. * * @return The Id of the current JVM. */ public static int getJVMId() { return m_jvmId; } private static String[] parseCommandLine( String cmdLine ) { ArrayList argList = new ArrayList(); StringBuffer arg = new StringBuffer(); boolean quoteMode = false; boolean escapeNextCharIfQuote = false; char c[] = cmdLine.toCharArray(); for ( int i = 0; i < cmdLine.length(); i++ ) { if ( ( c[i] == '\\' ) && !escapeNextCharIfQuote ) { escapeNextCharIfQuote = true; } else { if ( Character.isWhitespace( c[i] ) && ( quoteMode == false ) ) { if ( arg.length() > 0 ) { argList.add( arg.toString() ); arg.setLength( 0 ); } } else { if ( c[i] == '\"' ) { if ( escapeNextCharIfQuote == false ) { quoteMode = ( ( quoteMode == true ) ? false : true ); escapeNextCharIfQuote = false; continue; } else { // arg.append('\\'); escapeNextCharIfQuote = false; } arg.append( c[i] ); } else if ( c[i] == '\\' ) { if ( escapeNextCharIfQuote == true ) { escapeNextCharIfQuote = false; } arg.append( '\\' ); } else { if ( escapeNextCharIfQuote == true ) { arg.append( '\\' ); escapeNextCharIfQuote = false; } arg.append( c[i] ); } } // else } // else } // for if ( arg.length() > 0 ) { argList.add( arg.toString() ); } String[] args = new String[ argList.size() ]; argList.toArray( args ); return args; } /** * A more powerful replacement to the java.lang.Runtime.exec method. *

* When the JVM exits or is terminated for any reason, the Wrapper will * clean up any child processes launched with this method automatically * before shutting down or launching a new JVM. *

* This method is the same as calling

WrapperManager.exec(command, new WrapperProcessConfig());
*

* The returned WrapperProcess object can be used to control the child * process, supply input, or process output. *

* Professional Edition feature. * * @param command A specified system command in one String. * * @return A new WrapperProcess object for managing the subprocess. * * @throws IOException Will be thrown if an I/O error occurs * @throws NullPointerException If command is null. * @throws IllegalArgumentException If command is empty * @throws SecurityException If a SecurityManager is present and its * checkExec method doesn't allow creation of a * subprocess. * @throws WrapperJNIError If the native library has not been loaded or is in the * process of shutting down. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or if the native * library has not been loaded. * @throws UnsatisfiedLinkError If the posix_spawn function couldn't be found * * @see #isProfessionalEdition() * @see #exec(String command, WrapperProcessConfig config) * @see WrapperProcessConfig * @since Wrapper 3.4.0 */ public static WrapperProcess exec( String command ) throws SecurityException, IOException, NullPointerException, IllegalArgumentException, WrapperJNIError, WrapperLicenseError, UnsatisfiedLinkError { WrapperProcess proc = exec( command, new WrapperProcessConfig() ); return proc; } /** * A more powerful replacement to the java.lang.Runtime.exec method. *

* By configuring the WrapperProcessConfig object, it is possible to * control whether or not the child process will be automatically * cleaned up when the JVM exits or is terminated. It is also possible * to control how the child process is launched to work around memory * issues on some platforms. *

* For example, on Solaris when the JVM is very large, doing a fork will * duplicate the entire JVM's memory space and cause an out of memory * error or JVM crash, to avoid such memory problems the child process * can be launched using posix spawn as follows:

*

WrapperManager.exec( command, new WrapperProcessConfig().setStartType( WrapperProcessConfig.POSIX_SPAWN ) );
*

* Please review the WrapperProcessConfig class for a full list of * options. *

* The returned WrapperProcess object can be used to control the child * process, supply input, or process output. *

* Professional Edition feature. * * @param command A specified system command in one String. * @param config A WrapperProcessConfig object representing the Start/Run * Configurations of the subprocess * * @return A new WrapperProcess object for managing the subprocess. * * @throws IOException Will be thrown if an I/O error occurs * @throws NullPointerException If command is null. * @throws IllegalArgumentException If command is empty or the configuration is invalid * @throws SecurityException If a SecurityManager is present and its * checkExec method doesn't allow creation of a * subprocess. * @throws WrapperJNIError If the native library has not been loaded or is in the * process of shutting down. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or if the native * library has not been loaded. * @throws UnsatisfiedLinkError If the posix_spawn function couldn't be found * * @see #isProfessionalEdition() * @see WrapperProcessConfig * @since Wrapper 3.4.0 */ public static WrapperProcess exec( String command, WrapperProcessConfig config ) throws SecurityException, IOException, NullPointerException, IllegalArgumentException, WrapperJNIError, WrapperLicenseError, UnsatisfiedLinkError { if ( ( command == null ) || ( command.length() == 0 ) ) { throw new IllegalArgumentException( getRes().getString( "No command specified." ) ); } return exec( null, command, config ); } /** * A more powerful replacement to the java.lang.Runtime.exec method. *

* When the JVM exits or is terminated for any reason, the Wrapper will * clean up any child processes launched with this method automatically * before shutting down or launching a new JVM. *

* This method is the same as calling

WrapperManager.exec(cmdArray, new WrapperProcessConfig());
*

* The returned WrapperProcess object can be used to control the child * process, supply input, or process output. *

* Professional Edition feature. * * @param cmdArray A specified system command in array format for each * parameter a single element. * * @return A new WrapperProcess object for managing the subprocess * * @throws IOException Will be thrown at any error realated with Memory * allocation, or if the command does not exist. * @throws NullPointerException If cmdarray is null, or one of the elements * of cmdarray is null. * @throws IndexOutOfBoundsException If cmdarray is an empty array (has * length 0) * @throws SecurityException If a SecurityManager is present and its * checkExec method doesn't allow creation of a * subprocess. * @throws IllegalArgumentException If there are any problems with the * WrapperProcessConfig object. * @throws WrapperJNIError If the native library has not been loaded or is in the * process of shutting down. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or if the native * library has not been loaded. * @throws UnsatisfiedLinkError If the posix_spawn function couldn't be found * * @see #isProfessionalEdition() * @since Wrapper 3.4.0 */ public static WrapperProcess exec( String[] cmdArray ) throws SecurityException, IOException, NullPointerException, IndexOutOfBoundsException, IllegalArgumentException, WrapperJNIError, UnsatisfiedLinkError, WrapperLicenseError { WrapperProcess proc = exec( cmdArray, new WrapperProcessConfig() ); return proc; } /** * A more powerful replacement to the java.lang.Runtime.exec method. *

* By configuring the WrapperProcessConfig object, it is possible to * control whether or not the child process will be automatically * cleaned up when the JVM exits or is terminated. It is also possible * to control how the child process is launched to work around memory * issues on some platforms. *

* For example, on Solaris when the JVM is very large, doing a fork will * duplicate the entire JVM's memory space and cause an out of memory * error or JVM crash, to avoid such memory problems the child process * can be launched using posix spawn as follows:

*

WrapperManager.exec( cmdArray, new WrapperProcessConfig().setStartType( WrapperProcessConfig.POSIX_SPAWN ) );
*

* Please review the WrapperProcessConfig class for a full list of * options. *

* The returned WrapperProcess object can be used to control the child * process, supply input, or process output. *

* Professional Edition feature. * * @param cmdArray A specified system command in array format, for each * parameter a single element. * @param config A WrapperProcessConfig object representing the Start/Run * Configurations of the subprocess * * @return A new WrapperProcess object for managing the subprocess. * * @throws IOException Will be thrown if an I/O error occurs * @throws NullPointerException If cmdarray is null, or one of the elements * of cmdarray is null. * @throws IndexOutOfBoundsException If cmdarray is an empty array (has * length 0) * @throws SecurityException If a SecurityManager is present and its * checkExec method doesn't allow creation of a * subprocess. * @throws IllegalArgumentException If there are any problems with the * WrapperProcessConfig object. * @throws WrapperJNIError If the native library has not been loaded or is in the * process of shutting down. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or if the native * library has not been loaded. * @throws UnsatisfiedLinkError If the posix_spawn function couldn't be found * * @see #isProfessionalEdition() * @since Wrapper 3.4.0 */ public static WrapperProcess exec( String[] cmdArray, WrapperProcessConfig config ) throws SecurityException, IOException, NullPointerException, IndexOutOfBoundsException, IllegalArgumentException, WrapperJNIError, WrapperLicenseError, UnsatisfiedLinkError { return exec( cmdArray, null, config ); } /** * Executes an external command. */ private static WrapperProcess exec( String[] cmdArray, String cmdLine, WrapperProcessConfig config ) throws SecurityException, IOException, NullPointerException, IndexOutOfBoundsException, IllegalArgumentException, WrapperJNIError, WrapperLicenseError, UnsatisfiedLinkError { // If the cmdArray parameter is null then the cmdLine will be parsed into an a cmdArray. // Then both the cmdArray and cmdLine will be passed off to the native code. // The cmdLine may be null. assertProfessionalEdition(); if ( ( cmdArray == null ) && ( cmdLine == null ) ) { throw new NullPointerException( getRes().getString( "No command specified" ) ); } else if ( ( cmdArray != null) && ( cmdArray.length == 0 ) ) { throw new IndexOutOfBoundsException( getRes().getString( "cmdArray is empty" ) ); } if ( ( cmdArray == null ) && ( cmdLine != null ) ) { cmdArray = parseCommandLine( cmdLine ); } if ( config == null ) { throw new NullPointerException( getRes().getString( "config is null" ) ); } // Make sure the call stack has permission to execute this command. SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkExec( cmdArray[0] ); } // Keep track of how many threads are trying to execute child processes. // This is critical to avoid notification failures on shutdown. synchronized( WrapperManager.class ) { m_runningExecs++; } try { if ( isNativeLibraryOk() ) { for ( int i = 0; i < cmdArray.length; i++ ) { if ( cmdArray[i] == null ) { throw new NullPointerException( getRes().getString( "cmdarray[{0}]: Invalid element (isNull).", new Integer( i) ) ); } } // On UNIX platforms, we want to try and make sure the command is // valid before we run it to avoid problems later. Not necessary // on Windows. if ( !m_windows ) { if ( !new File( cmdArray[0] ).exists() ) { boolean found = false; String path = nativeWrapperGetEnv( "PATH" ); if ( path != null ) { String[] paths = path.split( File.pathSeparator ); for ( int i = 0; i < paths.length; i++ ) { File file = new File( paths[i] + File.separator + cmdArray[0] ); // m_outInfo.println( blu.getPath() ); if ( file.exists() ) { cmdArray[0] = file.getPath(); found = true; break; } } } if ( !found ) { throw new IOException(getRes().getString( "''{0}'' not found." , cmdArray[0] ) ); } } } if ( m_debug ) { for ( int j = 0; j < cmdArray.length; j++ ) { m_outDebug.println( "args[" + j + "] = " + cmdArray[j] ); } } return nativeExec( cmdArray, cmdLine, config.setEnvironment( config.getEnvironment() ), WrapperSystemPropertyUtil.getBooleanProperty( "wrapper.child.allowCWDOnSpawn", false ) ); } else { if ( m_stopped ) { // This message is logged when localization is no longer available. throw new WrapperJNIError( "Wrapper native library shutting down." ); } else { // This message is logged when localization is not available. throw new WrapperJNIError( "Wrapper native library not loaded." ); } } } finally { synchronized( WrapperManager.class ) { m_runningExecs--; if ( m_runningExecs <= 0 ) { WrapperManager.class.notifyAll(); } } } } /** * Returns true if the native library has been loaded successfully, false * otherwise. This value can switch to false on shutdown when the native * library can no longer be reliably referenced. * * @return True if the native library is loaded and available. */ public static boolean isNativeLibraryOk() { return m_libraryOK && ( !m_stopped ); } /** * Asserts that the Professional Edition of the Wrapper is being used and * that the native library is available. * * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or if the native * library has not been loaded. */ static void assertProfessionalEdition() throws WrapperLicenseError { if ( !m_libraryOK ) { throw new WrapperLicenseError( getRes().getString( "Requires that the Professional Edition native library be loaded. Please check for errors earlier in the log." ) ); } else if ( m_stopped ) { throw new WrapperLicenseError( getRes().getString( "Requires that the Professional Edition native library be loaded, but it has already been unloaded as part of the shutdown process." ) ); } else if ( !isProfessionalEdition() ) { throw new WrapperLicenseError( getRes().getString( "Requires the Professional Edition." ) ); } } /** * Returns true if the current JVM is Windows. * * @return True if this is Windows. * * @since Wrapper 3.5.1 */ public static boolean isWindows() { return m_windows; } /** * Returns true if the current JVM is Mac OSX. * * @return True if this is Mac OSX. * * @since Wrapper 3.5.1 */ public static boolean isMacOSX() { return m_macosx; } /** * Returns true if the current Wrapper edition has support for Professional * Edition features. * * False will also be returned if the native library has not been initialized correctly. * * @return True if professional features are supported. */ public static boolean isProfessionalEdition() { // Use a cached value rather than calling the JNI call here to avoid confusing errors on shutdown. return m_professionalEdition; } /** * Returns true if the current Wrapper edition has support for Standard * Edition features. * * False will also be returned if the native library has not been initialized correctly. * * @return True if standard features are supported. */ public static boolean isStandardEdition() { // Use a cached value rather than calling the JNI call here to avoid confusing errors on shutdown. return m_standardEdition; } /** * Fires a user event user_n specified in the conf file * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("fireUserEvent") * permission. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or if the native * library has not been loaded. */ public static void fireUserEvent( int eventNr ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperUserEventPermission( "fireUserEvent", String.valueOf( eventNr ) ) ); } if ( eventNr <= 0 || eventNr > 32767 ) { throw new java.lang.IllegalArgumentException( getRes().getString( "The user-event number must be in the range of 1-32767." ) ); } assertProfessionalEdition(); sendCommand( WRAPPER_MSG_FIRE_USER_EVENT, String.valueOf( eventNr ) ); } /** * Sets the title of the console in which the Wrapper is running. This * is currently only supported on Windows platforms. *

* As an alternative, it is also possible to set the console title from * within the wrapper.conf file using the wrapper.console.title property. * * @param title The new title. The specified string will be encoded * to a byte array using the default encoding for the * current platform. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("setConsoleTitle") * permission. * * @see WrapperPermission */ public static void setConsoleTitle( String title ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "setConsoleTitle" ) ); } if ( isNativeLibraryOk() ) { nativeSetConsoleTitle( title ); } } /** * Returns a WrapperUser object which describes the user under which the * Wrapper is currently running. Additional platform specific information * can be obtained by casting the object to a platform specific subclass. * WrapperWin32User, for example. * * @param groups True if the user's groups should be returned as well. * Requesting the groups that a user belongs to increases * the CPU load required to complete the call. * * @return An object describing the current user. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("getUser") permission. * * @see WrapperPermission */ public static WrapperUser getUser( boolean groups ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "getUser" ) ); } WrapperUser user = null; if ( isNativeLibraryOk() ) { user = nativeGetUser( groups ); } return user; } /** * Returns a WrapperUser object which describes the interactive user whose * desktop is being interacted with. When a service running on a Windows * platform has its interactive flag set, this method will return the user * who is currently logged in. Additional platform specific information * can be obtained by casting the object to a platform specific subclass. * WrapperWin32User, for example. *

* If a user is not currently logged on then this method will return null. * User code can repeatedly call this method to detect when a user has * logged in. To detect when a user has logged out, there are two options. * 1) The user code can continue to call this method until it returns null. * 2) Or if the WrapperListener method is being implemented, the * WrapperListener.controlEvent method will receive a WRAPPER_CTRL_LOGOFF_EVENT * event when the user logs out. *

* On XP systems, it is possible to switch to another account rather than * actually logging out. In such a case, the interactive user will be * the first user that logged in. This will also be the only user with * which the service will interact. If other users are logged in when the * interactive user logs out, the service will not automatically switch to * another logged in user. Rather, the next user to log in will become * the new user which the service will interact with. *

* This method will always return NULL on versions of NT prior to Windows * 2000. This can not be helped as some required functions were not added * to the windows API until NT version 5.0, also known as Windows 2000. * * @param groups True if the user's groups should be returned as well. * Requesting the groups that a user belongs to increases * the CPU load required to complete the call. * * @return The current interactive user, or null. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("getInteractiveUser") * permission. * * @see WrapperPermission */ public static WrapperUser getInteractiveUser( boolean groups ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "getInteractiveUser" ) ); } WrapperUser user = null; if ( isNativeLibraryOk() ) { user = nativeGetInteractiveUser( groups ); } return user; } /** * Returns a Properties object containing expanded the contents of the * configuration file used to launch the Wrapper. * * All properties are included so it is possible to define properties * not used by the Wrapper in the configuration file and have then * be available in this Properties object. * * @return The contents of the Wrapper configuration file. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("getProperties") * permission. * * @see WrapperPermission */ public static Properties getProperties() { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "getProperties" ) ); } return m_properties; } /** * Returns the PID of the Wrapper process. * * A PID of 0 will be returned if the JVM was launched standalone. * * This value can also be obtained using the 'wrapper.pid' system property. * * @return The PID of the Wrpper process. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("getWrapperPID") permission. * * @see WrapperPermission */ public static int getWrapperPID() { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "getWrapperPID" ) ); } return WrapperSystemPropertyUtil.getIntProperty( "wrapper.pid", 0 ); } /** * Returns the PID of the Java process. * * A PID of 0 will be returned if the native library has not been initialized. * * This value can also be obtained using the 'wrapper.java.pid' system property. * * @return The PID of the Java process. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("getJavaPID") permission. * * @see WrapperPermission */ public static int getJavaPID() { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "getJavaPID" ) ); } return WrapperSystemPropertyUtil.getIntProperty( "wrapper.java.pid", 0 ); } /** * Requests that the current JVM process request a thread dump. This is * the same as pressing CTRL-BREAK (under Windows) or CTRL-\ (under Unix) * in the the console in which Java is running. This method does nothing * if the native library is not loaded. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("requestThreadDump") * permission. * * @see WrapperPermission */ public static void requestThreadDump() { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "requestThreadDump" ) ); } if ( isNativeLibraryOk() ) { nativeRequestThreadDump(); } else { m_outInfo.println( getRes().getString( " wrapper library not loaded." ) ); } } /** * (Testing Method) Causes the WrapperManager to go into a state which makes the JVM appear * to be hung when viewed from the native Wrapper code. Does not have any effect when the * JVM is not being controlled from the native Wrapper. Useful for testing the Wrapper * functions. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("test.appearHung") permission. * * @see WrapperPermission */ public static void appearHung() { if ( m_disableTests ) { throw new IllegalStateException( getRes().getString( "Test methods have been disabled." ) ); } SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "test.appearHung" ) ); } m_outInfo.println( getRes().getString( "WARNING: Making JVM appear to be hung..." ) ); m_appearHung = true; } /** * (Testing Method) Causes the WrapperManager to go into a state which makes * the JVM appear to be sluggish when viewed from the native Wrapper code. * Each packet received from the Wrapper is delayed by the specified number * of seconds. * * If several packets are received in succession then this delay will be * cumulative. The delay reported by the Wrapper may appear to be quite a * bit different if multiple packets are being delayed in series. Some * packets, like pings, which are sent multiple times may also be reported * as being processed faster than this delay because the previous response * is what is actually being received. * * Does not have any effect when the JVM is not being controlled from the * native Wrapper. Useful for testing the Wrapper functions. * * @param slowSeconds The number of seconds to delay reponding to any incoming * commands from the wrapper. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("test.appearSlow") permission. * * @see WrapperPermission */ public static void appearSlow( int slowSeconds ) { if ( m_disableTests ) { throw new IllegalStateException( getRes().getString( "Test methods have been disabled." ) ); } SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "test.appearSlow" ) ); } if ( slowSeconds > 0 ) { m_outInfo.println( getRes().getString( "WARNING: Making JVM appear to be slow using a delay of {0} seconds...", new Integer( slowSeconds ) ) ); m_slowSeconds = slowSeconds; } else if ( m_slowSeconds > 0 ) { m_outInfo.println( getRes().getString( "Resetting the JVM delayed response to normal..." ) ); m_slowSeconds = 0; } } /** * @deprecated Removed as of 3.5.8 */ public static void appearOrphan() { } /** * (Testing Method) Cause an access violation within the Java code. Useful * for testing the Wrapper functions. This currently only crashes Sun * JVMs and takes advantage of Bug #4369043 which does not exist in newer * JVMs. Use of the accessViolationNative() method is preferred. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("test.accessViolation") * permission. * * @see WrapperPermission */ public static void accessViolation() { if ( m_disableTests ) { throw new IllegalStateException( getRes().getString( "Test methods have been disabled." ) ); } SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "test.accessViolation" ) ); } m_outInfo.println( getRes().getString( "WARNING: Attempting to cause an access violation..." ) ); try { Class c = Class.forName( "java.lang.String" ); java.lang.reflect.Method m = c.getDeclaredMethod( (String)null, (Class[])null ); } catch( NoSuchMethodException ex ) { // Correctly did not find method. access_violation attempt failed. Not Sun JVM? } catch( Exception ex ) { if ( ex instanceof NoSuchFieldException ) { // Can't catch this in a catch because the compiler doesn't think it is being // thrown. But it is thrown on IBM jvms at least // Correctly did not find method. access_violation attempt failed. Not Sun JVM? } else { // Shouldn't get here. ex.printStackTrace( m_outError ); } } m_outInfo.println( getRes().getString( " Attempt to cause access violation failed. JVM is still alive." ) ); } /** * (Testing Method) Cause an access violation within native JNI code. * Useful for testing the Wrapper functions. This currently causes the * access violation by attempting to write to a null pointer. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("test.accessViolationNative") * permission. * * @see WrapperPermission */ public static void accessViolationNative() { if ( m_disableTests ) { throw new IllegalStateException( getRes().getString( "Test methods have been disabled." ) ); } SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "test.accessViolationNative" ) ); } m_outInfo.println( getRes().getString( "WARNING: Attempting to cause an access violation..." ) ); if ( isNativeLibraryOk() ) { accessViolationInner(); m_outInfo.println( getRes().getString( " Attempt to cause access violation failed. JVM is still alive." ) ); } else { m_outInfo.println( getRes().getString( " wrapper library not loaded." ) ); } } /** * Returns true if the JVM was launched by the Wrapper application. False * if the JVM was launched manually without the Wrapper controlling it. * * @return True if the current JVM was launched by the Wrapper. */ public static boolean isControlledByNativeWrapper() { return m_key != null; } /** * Returns true if the Wrapper was launched as an NT service on Windows or * as a daemon process on UNIX platforms. False if launched as a console. * This can be useful if you wish to display a user interface when in * Console mode. On UNIX platforms, this is not as useful because an * X display may not be visible even if launched in a console. * * @return True if the Wrapper is running as an NT service or daemon * process. */ public static boolean isLaunchedAsService() { return m_service; } /** * Returns true if the JVM should ignore user logoff events. Mainly used * within WrapperListener.controlEvent() method implemenations. * @return True if user logoff events should be ignroed. */ public static boolean isIgnoreUserLogoffs() { return m_ignoreUserLogoffs; } /** * Returns true if the wrapper.debug property, or any of the logging * channels are set to DEBUG in the wrapper configuration file. Useful * for deciding whether or not to output certain information to the * console. * * @return True if the Wrapper is logging any Debug level output. */ public static boolean isDebugEnabled() { return m_debug; } /** * Internal method to let Wrapper classes decide whether or not to write finalizer log output. */ static boolean isLoggingFinalizers() { return m_logFinalizer; } /** * Start the Java side of the Wrapper code running. This will make it * possible for the native side of the Wrapper to detect that the Java * Wrapper is up and running. *

* This method must be called on startup and then can only be called once * so there is no reason for any security permission checks on this call. * * @param listener The WrapperListener instance which represents the * application being started. * @param args The argument list passed to the JVM when it was launched. */ public static void start( final WrapperListener listener, final String[] args ) { // As was done in the static initializer, we need to execute the following // code in a privileged action so it is not necessary for the calling code // to have the same privileges as the wrapper jar. // This is safe because this method can only be called once and that one call // will presumably be made on JVM startup. AccessController.doPrivileged( new PrivilegedAction() { public Object run() { privilegedStart( listener, args ); return null; } } ); } /** * Called by the start method within a PrivilegedAction. * * @param WrapperListener The WrapperListener instance which represents * the application being started. * @param args The argument list passed to the JVM when it was launched. */ private static void privilegedStart( WrapperListener listener, String[] args ) { // Check the SecurityManager here as it is possible that it was set before this call. checkSecurityManager(); // Just in case the user failed to provide an argument list, recover by creating one // here. This will avoid possible problems down stream. if ( args == null ) { args = new String[0]; } if ( m_debug ) { StringBuffer sb = new StringBuffer(); sb.append( "args[" ); for ( int i = 0; i < args.length; i++ ) { if ( i > 0 ) { sb.append( ", " ); } sb.append( "\"" ); sb.append( args[i] ); sb.append( "\"" ); } sb.append( "]" ); m_outDebug.println( getRes().getString( "{0} called by thread: {1}", "WrapperManager.start(a " + listener.getClass().getName() + ", " + sb.toString() + ")", Thread.currentThread().getName() ) ); } synchronized( WrapperManager.class ) { // Make sure that the class has not already been disposed. if ( m_disposed) { throw new IllegalStateException( getRes().getString( "WrapperManager has already been disposed." ) ); } if ( m_listener != null ) { throw new IllegalStateException( getRes().getString( "WrapperManager has already been started with a WrapperListener." ) ); } if ( listener == null ) { throw new IllegalStateException( getRes().getString( "A WrapperListener must be specified." ) ); } m_listener = listener; m_args = args; if ( m_debug ) { Thread thisThread = Thread.currentThread(); m_outDebug.println( getRes().getString( "Initial thread: {0} Priority: {1}", thisThread.getName(), new Integer( thisThread.getPriority() ) ) ); } // Setup the thread to handle backend communications. startRunner(); // If this JVM is being controlled by a native wrapper, then we want to // wait for the command to start. However, if this is a standalone // JVM, then we want to start now. if ( !isControlledByNativeWrapper() ) { startInner( true ); } } } /** * Returns true if the JVM is in the process of shutting down. This can be * useful to avoid starting long running processes when it is known that the * JVM will be shutting down shortly. * * @return true if the JVM is shutting down. */ public static boolean isShuttingDown() { return m_stopping; } private static class ShutdownLock extends Object { private final Thread m_thread; private int m_count; private ShutdownLock( Thread thread ) { m_thread = thread; } } /** * Increase the number of locks which will prevent the Wrapper from letting * the JVM process exit on shutdown. This is primarily useful around * calls to native JNI functions in daemon threads where it has been shown * that premature JVM exits can cause the JVM process to crash on shutdown. *

* Normal non-daemon threads should not require these locks as the very * fact that the non-daemon thread is still running will prevent the JVM * from shutting down. *

* It is possible to make multiple calls within a single thread. Each call * should always be paired with a call to releaseShutdownLock(). * * @throws WrapperShuttingDownException If called after the Wrapper has * already begun the shutdown of the * JVM. */ public static void requestShutdownLock() throws WrapperShuttingDownException { synchronized( WrapperManager.class ) { if ( m_stopping ) { throw new WrapperShuttingDownException(); } Thread thisThread = Thread.currentThread(); ShutdownLock lock = (ShutdownLock)m_shutdownLockMap.get( thisThread ); if ( lock == null ) { lock = new ShutdownLock( thisThread ); m_shutdownLockMap.put( thisThread, lock ); } lock.m_count++; m_shutdownLocks++; if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1} (New thread lock count: {2}, total lock count: {3})", "WrapperManager.requestShutdownLock()", thisThread.getName(), new Integer( lock.m_count ), new Integer( m_shutdownLocks ) ) ); } } } /** * Called by a thread which has previously called requestShutdownLock(). * * @throws IllgalStateException If called without first calling requestShutdownLock() from * the same thread. */ public static void releaseShutdownLock() throws IllegalStateException { synchronized( WrapperManager.class ) { Thread thisThread = Thread.currentThread(); ShutdownLock lock = (ShutdownLock)m_shutdownLockMap.get( thisThread ); if ( lock == null ) { throw new IllegalStateException( getRes().getString( "requestShutdownLock was not called from this thread." ) ); } lock.m_count--; m_shutdownLocks--; if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1} (New thread lock count: {2}, total lock count: {3})", "WrapperManager.releaseShutdownLock()", thisThread.getName(), new Integer( lock.m_count ), new Integer( m_shutdownLocks ) ) ); } if ( lock.m_count <= 0 ) { m_shutdownLockMap.remove( thisThread ); } WrapperManager.class.notify(); } } /** * Waits for any outstanding locks to be released before shutting down. */ private static void waitForShutdownLocks() { synchronized( WrapperManager.class ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "wait for {0} shutdown locks to be released.", new Integer(m_shutdownLocks ) ) ); } while ( m_shutdownLocks > 0 ) { try { WrapperManager.class.wait( 5000 ); } catch ( InterruptedException e ) { // Ignore and continue. } if ( m_shutdownLocks > 0 ) { m_outInfo.println( getRes().getString( "Waiting for {0} shutdown locks to be released..." , new Integer(m_shutdownLocks ) ) ); } } } } /** * Tells the native wrapper that the JVM wants to restart, then informs * all listeners that the JVM is about to shutdown before killing the JVM. *

* This method will not return. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("restart") permission. * * @see WrapperPermission */ public static void restart() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "restart" ) ); } m_stoppingInit = true; if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1}", "WrapperManager.restart()", Thread.currentThread().getName() ) ); } restartInner(); } /** * Tells the native wrapper that the JVM wants to restart, then informs * all listeners that the JVM is about to shutdown before killing the JVM. *

* This method requests that the JVM be restarted but then returns. This * allows components to initiate a JVM exit and then continue, allowing * a normal shutdown initiated by the JVM via shutdown hooks. In * applications which are designed to be shutdown when the user presses * CTRL-C, this may result in a cleaner shutdown. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("restart") permission. * * @see WrapperPermission */ public static void restartAndReturn() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "restart" ) ); } m_stoppingInit = true; synchronized( WrapperManager.class ) { if ( m_stopping ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1} (already stopping)", "WrapperManager.restartAndReturn()", Thread.currentThread().getName() ) ); } return; } else { if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1}", "WrapperManager.restartAndReturn()", Thread.currentThread().getName() ) ); } } } // To make this possible, we have to create a new thread to actually do the shutdown. Thread restarter = new Thread( "Wrapper-Restarter" ) { public void run() { restartInner(); } }; restarter.setDaemon( false ); restarter.start(); } /** * Common code used to restart the JVM. It is assumed that the calling * thread has has passed security checks before this is called. */ private static void restartInner() { boolean stopping; synchronized( WrapperManager.class ) { stopping = m_stopping; if ( !stopping ) { m_stopping = true; } } if ( !stopping ) { // Always send the restart command sendCommand( WRAPPER_MSG_RESTART, "restart" ); } // Give the Wrapper a chance to register the stop command before stopping. // This avoids any errors thrown by the Wrapper because the JVM died before // it was expected to. try { Thread.sleep( 1000 ); } catch ( InterruptedException e ) { } // This is safe because we are already checking for the privilege to restart the JVM // above. If we get this far then we want the Wrapper to be able to do everything // necessary to stop the JVM. AccessController.doPrivileged( new PrivilegedAction() { public Object run() { privilegedStopInner( 0 ); return null; } } ); } /** * Tells the native wrapper that the JVM wants to shut down, then informs * all listeners that the JVM is about to shutdown before killing the JVM. *

* This method will not return. * * @param exitCode The exit code that the Wrapper will return when it exits. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("stop") permission. * * @see WrapperPermission */ public static void stop( final int exitCode ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "stop" ) ); } m_stoppingInit = true; if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1}", "WrapperManager.stop(" + exitCode + ")", Thread.currentThread().getName() ) ); } stopCommon( exitCode, 1000 ); // This is safe because we are already checking for the privilege to stop the JVM // above. If we get this far then we want the Wrapper to be able to do everything // necessary to stop the JVM. AccessController.doPrivileged( new PrivilegedAction() { public Object run() { privilegedStopInner( exitCode ); return null; } } ); } /** * Tells the native wrapper that the JVM wants to shut down, then informs * all listeners that the JVM is about to shutdown before killing the JVM. *

* This method requests that the JVM be shutdown but then returns. This * allows components to initiate a JVM exit and then continue, allowing * a normal shutdown initiated by the JVM via shutdown hooks. In * applications which are designed to be shutdown when the user presses * CTRL-C, this may result in a cleaner shutdown. * * @param exitCode The exit code that the Wrapper will return when it exits. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("stop" ) permission. * * @see WrapperPermission */ public static void stopAndReturn( final int exitCode ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "stop" ) ); } m_stoppingInit = true; synchronized( WrapperManager.class ) { if ( m_stopping ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1} (already stopping)", "WrapperManager.stopAndReturn(" + exitCode + ")", Thread.currentThread().getName() ) ); } return; } else { if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1}", "WrapperManager.stopAndReturn(" + exitCode + ")", Thread.currentThread().getName() ) ); } } } // To make this possible, we have to create a new thread to actually do the shutdown. Thread stopper = new Thread( "Wrapper-Stopper" ) { public void run() { stopCommon( exitCode, 1000 ); // This is safe because we are already checking for the privilege to stop the JVM // above. If we get this far then we want the Wrapper to be able to do everything // necessary to stop the JVM. AccessController.doPrivileged( new PrivilegedAction() { public Object run() { privilegedStopInner( exitCode ); return null; } } ); } }; stopper.setDaemon( false ); stopper.start(); } /** * Tells the native wrapper that the JVM wants to shut down and then * promptly halts. Be careful when using this method as an application * will not be given a chance to shutdown cleanly. * * @param exitCode The exit code that the Wrapper will return when it exits. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("stopImmediate") permission. * * @see WrapperPermission */ public static void stopImmediate( final int exitCode ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "stopImmediate" ) ); } if ( m_debug ) { m_outDebug.println( getRes().getString( "{0} called by thread: {1}", "WrapperManager.stopImmediate(" + exitCode + ")", Thread.currentThread().getName() ) ); } stopCommon( exitCode, 250 ); signalStopped( exitCode ); // Really all done. if ( m_debug ) { m_outDebug.println( getRes().getString( "WrapperManger stopped due to {0}", getRes().getString( "Halt" ) ) ); } m_stopped = true; Runtime.getRuntime().halt( exitCode ); } /** * Signal the native wrapper that the startup is progressing but that more * time is needed. The current startup timeout will be extended if * necessary so it will be at least 'waitHint' milliseconds in the future. *

* This call will have no effect if the current startup timeout is already * more than 'waitHint' milliseconds in the future. * * @param waitHint Time in milliseconds to allow for the startup to * complete. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("signalStarting") permission. * * @see WrapperPermission */ public static void signalStarting( int waitHint ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "signalStarting" ) ); } sendCommand( WRAPPER_MSG_START_PENDING, Integer.toString( waitHint ) ); } /** * Signal the native wrapper that the shutdown is progressing but that more * time is needed. The current shutdown timeout will be extended if * necessary so it will be at least 'waitHint' milliseconds in the future. *

* This call will have no effect if the current shutdown timeout is already * more than 'waitHint' milliseconds in the future. * * @param waitHint Time in milliseconds to allow for the shutdown to * complete. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("signalStopping") permission. * * @see WrapperPermission */ public static void signalStopping( int waitHint ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "signalStopping" ) ); } m_stopping = true; sendCommand( WRAPPER_MSG_STOP_PENDING, Integer.toString( waitHint ) ); } /** * This method should not normally be called by user code as it is called * from within the stop and restart methods. However certain applications * which stop the JVM may need to call this method to let the wrapper code * know that the shutdown was intentional. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("signalStopped") permission. * * @see WrapperPermission */ public static void signalStopped( int exitCode ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "signalStopped" ) ); } m_stopping = true; sendCommand( WRAPPER_MSG_STOPPED, Integer.toString( exitCode ) ); // Give the socket time to actuall send the packet to the Wrapper // as this call is often immediately followed by a halt command. try { Thread.sleep( 250 ); } catch ( InterruptedException e ) { // Ignore. } } /** * Returns true if the ShutdownHook for the JVM has already been triggered. * Some code needs to know whether or not the system is shutting down. * * @return True if the ShutdownHook for the JVM has already been triggered. */ public static boolean hasShutdownHookBeenTriggered() { return m_hookTriggered; } /** * Requests that the Wrapper log a message at the specified log level. * If the JVM is not being managed by the Wrapper then calls to this * method will be ignored. This method has been optimized to ignore * messages at a log level which will not be logged given the current * log levels of the Wrapper. *

* Log messages will currently by trimmed by the Wrapper at 4k (4096 bytes). *

* Because of differences in the way console output is collected and * messages logged via this method, it is expected that interspersed * console and log messages will not be in the correct order in the * resulting log file. *

* This method was added to allow simple logging to the wrapper.log * file. This is not meant to be a full featured log file and should * not be used as such. Please look into a logging package for most * application logging. * * @param logLevel The level to log the message at can be one of * WRAPPER_LOG_LEVEL_DEBUG, WRAPPER_LOG_LEVEL_INFO, * WRAPPER_LOG_LEVEL_STATUS, WRAPPER_LOG_LEVEL_WARN, * WRAPPER_LOG_LEVEL_ERROR, or WRAPPER_LOG_LEVEL_FATAL. * @param message The message to be logged. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("log") permission. * * @see WrapperPermission */ public static void log( int logLevel, String message ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "log" ) ); } // Make sure that the logLevel is valid to avoid problems with the // command sent to the server. if ( ( logLevel < WRAPPER_LOG_LEVEL_DEBUG ) || ( logLevel > WRAPPER_LOG_LEVEL_NOTICE ) ) { throw new IllegalArgumentException( getRes().getString( "The specified logLevel is not valid." ) ); } if ( message == null ) { throw new IllegalArgumentException( getRes().getString( "The message parameter can not be null." ) ); } if ( m_lowLogLevel <= logLevel ) { sendCommand( (byte)( WRAPPER_MSG_LOG + logLevel ), message ); } } /** * Returns an array of all registered services. This method is only * supported on Windows platforms which support services. Calling this * method on other platforms will result in null being returned. * * @return An array of services. * * @throws SecurityException If a SecurityManager has not been set in the * JVM or if the calling code has not been * granted the WrapperPermission "listServices" * permission. A SecurityManager is required * for this operation because this method makes * it possible to learn a great deal about the * state of the system. * * @see WrapperPermission */ public static WrapperWin32Service[] listServices() throws SecurityException { SecurityManager sm = System.getSecurityManager(); if ( sm == null ) { throw new SecurityException( getRes().getString( "A SecurityManager has not yet been set." ) ); } else { sm.checkPermission( new WrapperPermission( "listServices" ) ); } if ( isNativeLibraryOk() ) { return nativeListServices(); } else { return null; } } /** * Sends a service control code to the specified service. The state of the * service should be tested on return. If the service was not currently * running then the control code will not be sent. *

* The control code sent can be one of the system control codes: * WrapperManager.SERVICE_CONTROL_CODE_START, * WrapperManager.SERVICE_CONTROL_CODE_STOP, * WrapperManager.SERVICE_CONTROL_CODE_PAUSE, * WrapperManager.SERVICE_CONTROL_CODE_CONTINUE, or * WrapperManager.SERVICE_CONTROL_CODE_INTERROGATE. In addition, user * defined codes in the range 128-255 can also be sent. * * @param serviceName Name of the Windows service which will receive the * control code. * @param controlCode The actual control code to be sent. User defined * control codes should be in the range 128-255. * * @return A WrapperWin32Service containing the last known status of the * service after sending the control code. This will be null if * the currently platform is not a version of Windows which * supports services. * * @throws WrapperServiceException If there are any problems accessing the * specified service. * @throws SecurityException If a SecurityManager has not been set in the * JVM or if the calling code has not been * granted the WrapperServicePermission * permission for the specified service and * control code. A SecurityManager is required * for this operation because this method makes * it possible to control any service on the * system, which is of course rather dangerous. * * @see WrapperServicePermission */ public static WrapperWin32Service sendServiceControlCode( String serviceName, int controlCode ) throws WrapperServiceException, SecurityException { SecurityManager sm = System.getSecurityManager(); if ( sm == null ) { throw new SecurityException( getRes().getString( "A SecurityManager has not yet been set." ) ); } else { String action; switch( controlCode ) { case SERVICE_CONTROL_CODE_START: action = WrapperServicePermission.ACTION_START; break; case SERVICE_CONTROL_CODE_STOP: action = WrapperServicePermission.ACTION_STOP; break; case SERVICE_CONTROL_CODE_PAUSE: action = WrapperServicePermission.ACTION_PAUSE; break; case SERVICE_CONTROL_CODE_CONTINUE: action = WrapperServicePermission.ACTION_CONTINUE; break; case SERVICE_CONTROL_CODE_INTERROGATE: action = WrapperServicePermission.ACTION_INTERROGATE; break; default: if ( ( controlCode >= 128 ) && ( controlCode <= 255 ) ) { action = WrapperServicePermission.ACTION_USER_CODE; } else { throw new IllegalArgumentException( getRes().getString( "The specified controlCode is invalid." ) ); } break; } sm.checkPermission( new WrapperServicePermission( serviceName, action ) ); } WrapperWin32Service service = null; if ( isNativeLibraryOk() ) { service = nativeSendServiceControlCode( serviceName, controlCode ); } return service; } /** * Adds a WrapperEventListener which will receive WrapperEvents. The * specific events can be controlled using the mask parameter. This API * was chosen to allow for additional events in the future. * * To avoid future compatibility problems, WrapperEventListeners should * always test the class of an event before making use of it. This will * avoid problems caused by new event classes added in future versions * of the Wrapper. * * This method should only be called once for a given WrapperEventListener. * Build up a single mask to receive events of multiple types. * * @param listener WrapperEventListener to be start receiving events. * @param mask A mask specifying the event types that the listener is * interrested in receiving. See the WrapperEventListener * class for a full list of flags. A mask is created by * combining multiple flags using the binary '|' OR operator. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the appropriate * WrapperEventPermission(...) permission. * * @see WrapperEventPermission */ public static void addWrapperEventListener( WrapperEventListener listener, long mask ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { StringBuffer sb = new StringBuffer(); boolean first = true; if ( ( mask & WrapperEventListener.EVENT_FLAG_SERVICE ) != 0 ) { first = false; sb.append( WrapperEventPermission.EVENT_TYPE_SERVICE ); } if ( ( mask & WrapperEventListener.EVENT_FLAG_CONTROL ) != 0 ) { if ( first ) { first = false; } else { sb.append( "," ); } sb.append( WrapperEventPermission.EVENT_TYPE_CONTROL ); } if ( ( mask & WrapperEventListener.EVENT_FLAG_CORE ) != 0 ) { if ( first ) { first = false; } else { sb.append( "," ); } sb.append( WrapperEventPermission.EVENT_TYPE_CORE ); } sm.checkPermission( new WrapperEventPermission( sb.toString() ) ); } synchronized( WrapperManager.class ) { WrapperEventListenerMask listenerMask = new WrapperEventListenerMask(); listenerMask.m_listener = listener; listenerMask.m_mask = mask; m_wrapperEventListenerMaskList.add( listenerMask ); m_wrapperEventListenerMasks = null; } updateWrapperEventListenerFlags(); } /** * Removes a WrapperEventListener so it will not longer receive WrapperEvents. * * @param listener WrapperEventListener to be stop receiving events. * * @throws SecurityException If a SecurityManager is present and the * calling thread does not have the * WrapperPermission("removeWrapperEventListener") * permission. * * @see WrapperPermission */ public static void removeWrapperEventListener( WrapperEventListener listener ) { SecurityManager sm = System.getSecurityManager(); if ( sm != null ) { sm.checkPermission( new WrapperPermission( "removeWrapperEventListener" ) ); } synchronized( WrapperManager.class ) { // Look for the first instance of a given listener in the list. for ( Iterator iter = m_wrapperEventListenerMaskList.iterator(); iter.hasNext(); ) { WrapperEventListenerMask listenerMask = (WrapperEventListenerMask)iter.next(); if ( listenerMask.m_listener == listener ) { iter.remove(); m_wrapperEventListenerMasks = null; break; } } } updateWrapperEventListenerFlags(); } /** * Returns the Log file currently being used by the Wrapper. If log file * rolling is enabled in the Wrapper then this file may change over time. * * @throws IllegalStateException If this method is called before the Wrapper * instructs this class to start the user * application. */ public static File getWrapperLogFile() { File logFile = m_logFile; if ( logFile == null ) { throw new IllegalStateException( getRes().getString( "Not yet initialized." ) ); } return logFile; } /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * This class can not be instantiated. */ private WrapperManager() { } /*--------------------------------------------------------------- * Private methods *-------------------------------------------------------------*/ /** * Checks for the existence of a SecurityManager and then makes sure that * the Wrapper jar has been granted AllPermissions. If not then a warning * will be displayed as this will most likely result in the Wrapper * failing to function correctly. * * This method is called at various points in the startup as it is possible * and in fact likely that any SecurityManager will be set by user code * during or shortly after initialization. Once a SecurityManager has * been located and tested then this method will become a noop. */ private static void checkSecurityManager() { if ( m_securityManagerChecked ) { return; } SecurityManager securityManager = System.getSecurityManager(); if ( securityManager != null ) { if ( m_debug ) { m_outDebug.println(getRes().getString( "Detected a SecurityManager: {0} " , securityManager.getClass().getName() ) ); } try { securityManager.checkPermission( new java.security.AllPermission() ); } catch ( SecurityException e ) { m_outDebug.println(); m_outDebug.println( getRes().getString( "WARNING - Detected that a SecurityManager has been installed but the " ) ); m_outDebug.println( getRes().getString( " wrapper.jar has not been granted the java.security.AllPermission" ) ); m_outDebug.println( getRes().getString( " permission. This will most likely result in SecurityExceptions" ) ); m_outDebug.println( getRes().getString( " being thrown by the Wrapper." ) ); m_outDebug.println(); } // Always set the flag. m_securityManagerChecked = true; } } /** * Returns an array of WrapperEventListenerMask instances which can * be safely used outside of synchronization. * * @return An array of WrapperEventListenerMask instances. */ private static WrapperEventListenerMask[] getWrapperEventListenerMasks() { WrapperEventListenerMask[] listenerMasks = m_wrapperEventListenerMasks; if ( listenerMasks == null ) { synchronized( WrapperManager.class ) { if ( listenerMasks == null ) { listenerMasks = new WrapperEventListenerMask[m_wrapperEventListenerMaskList.size()]; m_wrapperEventListenerMaskList.toArray( listenerMasks ); m_wrapperEventListenerMasks = listenerMasks; } } } return listenerMasks; } /** * Updates the internal flags based on the WrapperEventListeners currently * registered. */ private static void updateWrapperEventListenerFlags() { boolean core = false; WrapperEventListenerMask[] listenerMasks = getWrapperEventListenerMasks(); for ( int i = 0; i < listenerMasks.length; i++ ) { long mask = listenerMasks[i].m_mask; // See whether particular event types are required. core = core | ( ( mask & WrapperEventListener.EVENT_FLAG_CORE ) != 0 ); } m_produceCoreEvents = core; } /** * Notifies registered listeners that an event has been fired. * * @param event Event to notify the listeners of. */ private static void fireWrapperEvent( WrapperEvent event ) { long eventMask = event.getFlags(); WrapperEventListenerMask[] listenerMasks = getWrapperEventListenerMasks(); for ( int i = 0; i < listenerMasks.length; i++ ) { long listenerMask = listenerMasks[i].m_mask; // See if the event should be passed to this listner. if ( ( listenerMask & eventMask ) != 0 ) { // The listener wants the event. WrapperEventListener listener = listenerMasks[i].m_listener; try { listener.fired( event ); } catch ( Throwable t ) { m_outError.println( getRes().getString( "Encountered an uncaught exception while notifying WrapperEventListener of an event:" ) ); t.printStackTrace( m_outError ); } } } } /** * Executed code common to the stop and stopImmediate methods. */ private static void stopCommon( int exitCode, int delay ) { boolean stopping; synchronized( WrapperManager.class ) { stopping = m_stopping; if ( !stopping ) { m_stopping = true; } } if ( !stopping ) { // Always send the stop command sendCommand( WRAPPER_MSG_STOP, Integer.toString( exitCode ) ); if ( delay > 0 ) { // Give the Wrapper a chance to register the stop command before stopping. // This avoids any errors thrown by the Wrapper because the JVM died before // it was expected to. if ( m_debug ) { m_outDebug.println( getRes().getString( "Pausing for {0}ms to allow a clean shutdown...", new Integer( delay ) ) ); } try { Thread.sleep( delay ); } catch ( InterruptedException e ) { } } } } /** * Dispose of all resources used by the WrapperManager. Closes the server * socket which is used to listen for events from the Wrapper process. */ private static void dispose() { synchronized( WrapperManager.class ) { m_disposed = true; // Close the open backend if it exists. closeBackend(); // Give the Connection Thread a chance to stop itself. try { Thread.sleep( 500 ); } catch ( InterruptedException e ) { } } } /** * Called by startInner when the WrapperListner.start method has completed. * * Only called when WrapperManager.class is synchronized. */ private static void startCompleted() { m_startedTicks = getTicks(); // Let the startup thread die since the application has been started. m_startupRunner = null; // Check the SecurityManager here as it is possible that it was set in the // listener's start method. checkSecurityManager(); // Signal that the application has started. signalStarted(); // Wake up any threads waiting for this. WrapperManager.class.notifyAll(); } /** * Informs the listener that it should start. * * WrapperManager.class will be synchronized when called. * * @param block True if this call should block for the WrapperListener.start * method to complete. This is true when java is being run in * standalone mode without the Wrapper. */ private static void startInner( boolean block ) { m_starting = true; // Do any setup which should happen just before we actually start the application. checkTmpDir(); // This method can be called from the connection thread which must be a // daemon thread by design. We need to call the WrapperListener.start method // from a non-daemon thread. This means that if the current thread is a // daemon we need to launch a new thread while we wait for the start method // to return. if ( m_listener == null ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "No WrapperListener has been set. Nothing to start." ) ); } startCompleted(); } else { if ( m_debug ) { m_outDebug.println( getRes().getString( "calling WrapperListener.start()" ) ); } // These arrays aren't pretty, but we need final variables for the inline // class and this makes it possible to get the values back. final Integer[] resultF = new Integer[1]; final Throwable[] tF = new Throwable[1]; // Start in a dedicated thread. Thread startRunner = new Thread( "WrapperListener_start_runner" ) { public void run() { if ( m_debug ) { m_outDebug.println( getRes().getString( "WrapperListener.start runner thread started." ) ); } // If the calling thread was the Backend handler then it is running at a higher priority. // We need to restore the thread priority to the default before proceeding to make sure // that the rest of the application runs at the correct priority. Thread thisThread = Thread.currentThread(); thisThread.setPriority( Thread.NORM_PRIORITY ); if ( m_debug ) { m_outDebug.println( getRes().getString( "Application start main thread: {0} Priority: {1}", thisThread.getName(), new Integer( thisThread.getPriority() ) ) ); } try { // This is user code, so don't trust it. try { resultF[0] = m_listener.start( m_args ); } catch ( Throwable t ) { tF[0] = t; } } finally { // Make sure the rest of this thread does not fall behind the application. thisThread.setPriority( Thread.MAX_PRIORITY ); // Now that we are back, handle the results. if ( tF[0] != null ) { m_outError.println( getRes().getString( "Error in WrapperListener.start callback. {0}", tF[0] ) ); tF[0].printStackTrace( m_outError ); // Kill the JVM, but don't tell the wrapper that we want to stop. // This may be a problem with this instantiation only. privilegedStopInner( 1 ); // Won't make it here. return; } if ( m_debug ) { m_outDebug.println( getRes().getString( "returned from WrapperListener.start()" ) ); } if ( resultF[0] != null ) { int exitCode = resultF[0].intValue(); if ( m_debug ) { m_outDebug.println( getRes().getString( "WrapperListener.start() returned an exit code of {0}.", new Integer( exitCode ) ) ); } // Signal the native code. WrapperManager.stop( exitCode ); // Won't make it here. return; } synchronized( WrapperManager.class ) { startCompleted(); } if ( m_debug ) { m_outDebug.println( getRes().getString( "WrapperListener.start runner thread stopped." ) ); } } } }; startRunner.setDaemon( false ); startRunner.start(); if ( block ) { // Wait for the start runner to complete. if ( m_debug ) { m_outDebug.println( getRes().getString( "Waiting for WrapperListener.start runner thread to complete." ) ); } while ( ( startRunner != null ) && ( startRunner.isAlive() ) ) { try { WrapperManager.class.wait(); } catch ( InterruptedException e ) { // Ignore and keep waiting. } } } } } private static void shutdownJVM( int exitCode ) { if ( m_debug ) { m_outDebug.println(getRes().getString( "shutdownJVM({0}) Thread: {1}", new Integer( exitCode ), Thread.currentThread().getName() ) ); } // Make sure that any shutdown locks are released. waitForShutdownLocks(); // Signal that the application has stopped and the JVM is about to shutdown. signalStopped( exitCode ); // Dispose the wrapper. dispose(); m_shutdownJVMComplete = true; // Do not call System.exit if this is the ShutdownHook if ( Thread.currentThread() == m_hook ) { // This is the shutdown hook, so fall through because things are // already shutting down. } else { if ( m_debug ) { m_outDebug.println(getRes().getString( "calling System.exit({0})", new Integer( exitCode ) ) ); } safeSystemExit( exitCode ); } } /** * A user ran into a JVM bug where a call to System exit was causing an * IllegalThreadStateException to be thrown. Not sure how widespread * this problem is. But it is easy to avoid it causing serious problems * for the wrapper. */ private static void safeSystemExit( int exitCode ) { // Really all done. if ( m_debug ) { m_outDebug.println( getRes().getString( "WrapperManger stopped due to {0}", getRes().getString( "System Exit" ) ) ); } m_stopped = true; try { System.exit( exitCode ); } catch ( IllegalThreadStateException e ) { m_outError.println( getRes().getString( "Attempted System.exit({0}) call failed: {1}" , new Integer( exitCode ), e.toString() ) ); m_outError.println( getRes().getString( " Trying Runtime.halt({0})", new Integer( exitCode ) ) ); Runtime.getRuntime().halt( exitCode ); } } /** * Informs the listener that the JVM will be shut down. * * This should only be called from within a PrivilegedAction or in a * context that came from a PrivilegedAction. */ private static void privilegedStopInner( int exitCode ) { boolean block; synchronized( WrapperManager.class ) { // Always set the stopping flag. (Depending on how the shutdown was initiated, it may already be set.) m_stopping = true; // Only one thread can be allowed to continue. if ( m_stoppingThread == null ) { m_stoppingThread = Thread.currentThread(); block = false; } else { if ( Thread.currentThread() == m_stoppingThread ) { throw new IllegalStateException( getRes().getString( "WrapperManager.stop() can not be called recursively." ) ); } block = true; } } if ( block ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Thread, {0}, waiting for the JVM to exit.", Thread.currentThread().getName() ) ); if ( Thread.currentThread() == m_hook ) { if ( !m_hookRemoveFailed ) { m_outDebug.println( getRes().getString( "System.exit appears to have been called from within the\n WrapperListener.stop() method. If possible the application\n should be modified to avoid this behavior.\n To avoid a deadlock, this thread will only wait 5 seconds\n for the application to shutdown. This may result in the\n application failing to shutdown completely before the JVM\n exits. Removing the offending System.exit call will\n resolve this." ) ); } } } // This thread needs to be put into an infinite loop until the JVM exits. // This thread can not be allowed to return to the caller, but another // thread is already responsible for shutting down the JVM, so this // one can do nothing but wait. int loops = 0; int wait = 50; while( true ) { try { Thread.sleep( wait ); } catch ( InterruptedException e ) { } // If this is the wrapper's shutdown hook then we only want to loop until // the shutdownJVM method has completed. We will only get into this state // if user code calls System.exit from within the WrapperListener.stop // method. Failing to return here will cause the shutdown process to hang. // If the user code calls System.exit directly in the stop method then the // m_shutdownJVMComplete flag will never be set. Always time out after // 5 seconds so the JVM will not hang in such cases. if ( Thread.currentThread() == m_hook ) { if ( m_shutdownJVMComplete || ( loops > 5000 / wait ) ) { if ( !m_shutdownJVMComplete ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Thread, {0}, continuing after 5 seconds.", Thread.currentThread().getName() ) ); } } // To keep the wrapper from showing a JVM exited unexpectedly message // on shutdown, tell the wrapper that we are ready to stop. // If the WrapperListener.stop method is taking a long time, we will // also get here. In that case, the Wrapper will still wait for // the configured exit timeout before killing the JVM process. // In theory, the shutdown process of an application will only call // System.exit after the shutdown is complete so this should be Ok. // Use the exit code from the thread which initiated the call rather // than this call as that one is the one we really want. signalStopped( m_exitCode ); return; } } loops++; } } if ( m_debug ) { m_outDebug.println( getRes().getString( "Thread, {0}, handling the shutdown process.", Thread.currentThread().getName() ) ); } m_exitCode = exitCode; // If appropriate, unregister the shutdown hook. This must be done before the // user stop code is called to avoid nested shutdowns. if ( Thread.currentThread() != m_hook ) { // We do not want the ShutdownHook to execute, so unregister it before calling exit. // It can't be unregistered if it has already fired however. The only way that this // could happen is if user code calls System.exit from within the listener stop // method. if ( ( !m_hookTriggered ) && ( m_hook != null ) ) { // Remove the shutdown hook. try { Runtime.getRuntime().removeShutdownHook( m_hook ); } catch ( AccessControlException e ) { // This can happen if the security policy is not setup correctly. m_outError.println( getRes().getString( "Unable to remove the Wrapper''s shudownhook: {0}", e ) ); m_hookRemoveFailed = true; } } } // Only stop the listener if the app has been asked to start. Does not need to have actually started. int code = exitCode; if ( ( m_listenerForceStop && m_starting ) || m_started ) { // This method can be called from the connection thread which must be a // daemon thread by design. We need to call the WrapperListener.stop method // from a non-daemon thread. This means that if the current thread is a // daemon we need to launch a new thread while we wait for the stop method // to return. if ( m_listener == null ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "No WrapperListener has been set. Nothing to stop." ) ); } } else { if ( m_debug ) { m_outDebug.println( getRes().getString( "calling listener.stop()" ) ); } if ( Thread.currentThread().isDaemon() ) { // This array isn't pretty, but we need final variables for the inline // class and this makes it possible to get the values back. final Integer[] codeF = new Integer[] {new Integer(code)}; // Start in a dedicated thread. Thread stopRunner = new Thread( "WrapperListener_stop_runner" ) { public void run() { if ( m_debug ) { m_outDebug.println( getRes().getString( "WrapperListener.stop runner thread started." ) ); } // If the calling thread was the Backend handler then it is running at a higher priority. // We need to restore the thread priority to the default before proceeding to make sure // that the rest of the application runs at the correct priority. Thread thisThread = Thread.currentThread(); thisThread.setPriority( Thread.NORM_PRIORITY ); if ( m_debug ) { m_outDebug.println( getRes().getString( "Application stop main thread: {0} Priority: {1}", thisThread.getName(), new Integer( thisThread.getPriority() ) ) ); } try { // This is user code, so don't trust it. try { codeF[0] = new Integer( m_listener.stop( codeF[0].intValue() ) ); } catch ( Throwable t ) { m_outError.println( getRes().getString( "Error in WrapperListener.stop callback." ) ); t.printStackTrace( m_outError ); } } finally { if ( m_debug ) { m_outDebug.println( getRes().getString( "WrapperListener.stop runner thread stopped." ) ); } } } }; stopRunner.setDaemon( false ); stopRunner.start(); // Wait for the stop runner to complete. if ( m_debug ) { m_outDebug.println( getRes().getString( "Waiting for WrapperListener.stop runner thread to complete." ) ); } while ( ( stopRunner != null ) && ( stopRunner.isAlive() ) ) { try { stopRunner.join(); stopRunner = null; } catch ( InterruptedException e ) { // Ignore and keep waiting. } } // Get the exit code back from the array. code = codeF[0].intValue(); } else { // This is user code, so don't trust it. try { code = m_listener.stop( code ); } catch ( Throwable t ) { m_outError.println( getRes().getString( "Error in WrapperListener.stop callback." ) ); t.printStackTrace( m_outError ); } } if ( m_debug ) { m_outDebug.println( getRes().getString( "returned from listener.stop() -> {0}", new Integer( code ) ) ); } } } shutdownJVM( code ); } private static void signalStarted() { sendCommand( WRAPPER_MSG_STARTED, "" ); m_started = true; } /** * Called by the native code when a control event is trapped by native code. * Can have the values: WRAPPER_CTRL_C_EVENT, WRAPPER_CTRL_CLOSE_EVENT, * WRAPPER_CTRL_LOGOFF_EVENT, WRAPPER_CTRL_SHUTDOWN_EVENT, * WRAPPER_CTRL_TERM_EVENT, or WRAPPER_CTRL_HUP_EVENT. */ private static void controlEvent( int event ) { String eventName; boolean ignore; switch( event ) { case WRAPPER_CTRL_C_EVENT: eventName = "WRAPPER_CTRL_C_EVENT"; ignore = m_ignoreSignals; break; case WRAPPER_CTRL_CLOSE_EVENT: eventName = "WRAPPER_CTRL_CLOSE_EVENT"; ignore = m_ignoreSignals; break; case WRAPPER_CTRL_LOGOFF_EVENT: eventName = "WRAPPER_CTRL_LOGOFF_EVENT"; ignore = false; break; case WRAPPER_CTRL_SHUTDOWN_EVENT: eventName = "WRAPPER_CTRL_SHUTDOWN_EVENT"; ignore = false; break; case WRAPPER_CTRL_TERM_EVENT: eventName = "WRAPPER_CTRL_TERM_EVENT"; ignore = m_ignoreSignals; break; case WRAPPER_CTRL_HUP_EVENT: eventName = "WRAPPER_CTRL_HUP_EVENT"; ignore = m_ignoreSignals; break; case WRAPPER_CTRL_USR1_EVENT: eventName = "WRAPPER_CTRL_USR1_EVENT"; ignore = m_ignoreSignals; break; case WRAPPER_CTRL_USR2_EVENT: eventName = "WRAPPER_CTRL_USR2_EVENT"; ignore = m_ignoreSignals; break; default: eventName = getRes().getString( "Unexpected event: {0}", new Integer( event ) ); ignore = false; break; } WrapperControlEvent controlEvent = new WrapperControlEvent( event, eventName ); if ( ignore ) { // Preconsume the event if it is set to be ignored, but go ahead and fire it so // user can can still have the oportunity to recognize it. controlEvent.consume(); } fireWrapperEvent( controlEvent ); if ( ignore ) { // Event will always be consumed. if ( m_debug ) { m_outDebug.println( getRes().getString( "Ignoring control event({0})", eventName ) ); } } else { if ( controlEvent.isConsumed() ) { if ( m_debug ) { m_outDebug.println(getRes().getString( "Control event({0}) was consumed by user listener.", eventName ) ); } } else { if ( m_debug ) { m_outDebug.println(getRes().getString( "Processing control event({0})", eventName ) ); } // This is user code, so don't trust it. if ( m_listener != null ) { try { m_listener.controlEvent( event ); } catch ( Throwable t ) { m_outError.println( getRes().getString( "Error in WrapperListener.controlEvent callback." ) ); t.printStackTrace( m_outError ); } } else { // A listener was never registered. Always respond by exiting. // This can happen if the user does not initialize things correctly. stop( 0 ); } } } } /** * Parses a long tab separated string of properties into an internal * properties object. Actual tabs are escaped by real tabs. */ private static char PROPERTY_SEPARATOR = '\t'; private static void readProperties( String rawProps ) { WrapperProperties properties = new WrapperProperties(); int len = rawProps.length(); int first = 0; while ( first < len ) { StringBuffer sb = new StringBuffer(); boolean foundEnd = false; do { int pos = rawProps.indexOf( PROPERTY_SEPARATOR, first ); if ( pos >= 0 ) { if ( pos > 0 ) { sb.append( rawProps.substring( first, pos ) ); } if ( pos < len - 1 ) { if ( rawProps.charAt( pos + 1 ) == PROPERTY_SEPARATOR ) { // Two separators in a row, it was escaped. sb.append( PROPERTY_SEPARATOR ); first = pos + 2; } else { foundEnd = true; first = pos + 1; } } else { foundEnd = true; first = pos + 1; } } else { // No more separators. The rest is the last property. sb.append( rawProps.substring( first ) ); foundEnd = true; first = len; } } while ( !foundEnd ); String property = sb.toString(); // Parse the property. int pos = property.indexOf( '=' ); if ( pos > 0 ) { String key = property.substring( 0, pos ); String value; if ( pos < property.length() - 1 ) { value = property.substring( pos + 1 ); } else { value = ""; } properties.setProperty( key, value ); // Process special properties if ( key.equals( "wrapper.ignore_user_logoffs" ) ) { m_ignoreUserLogoffs = value.equalsIgnoreCase( "true" ); } } } // Lock the properties object and store it. properties.lock(); m_properties = properties; } /** * Opens a socket to the Wrapper process. */ private static synchronized void openBackendSocket() { if ( m_debug ) { m_outDebug.println( getRes().getString( "Open socket to wrapper...{0}", Thread.currentThread().getName() ) ); } InetAddress iNetAddress; try { iNetAddress = InetAddress.getByName( m_wrapperPortAddress ); } catch ( UnknownHostException e ) { // This is pretty fatal. m_outError.println( getRes().getString( "Unable to resolve localhost name: {0}", e ) ); m_outError.println( getRes().getString( "Exiting JVM..." ) ); stop( 1 ); return; // please the compiler } // If the user has specified a specific port to use then we want to try that first. boolean connected = false; int tryPort; boolean fixedPort; if ( m_jvmPort >= 0 ) { tryPort = m_jvmPort; fixedPort = true; } else { tryPort = m_jvmPortMin; fixedPort = false; } // Loop until we find a port we can connect using. SocketException causeException = null; do { try { m_backendSocket = new Socket( iNetAddress, m_port, iNetAddress, tryPort ); if ( m_debug ) { m_outDebug.println(getRes().getString( "Opened Socket from {0} to {1}", new Integer( tryPort ), new Integer( m_port ) ) ); } connected = true; break; } catch ( SocketException e ) { String eMessage = e.getMessage(); if ( e instanceof ConnectException ) { m_outError.println(getRes().getString( "Failed to connect to the Wrapper at port {0}. Cause: {1}", new Integer( m_port ), e ) ); // This is fatal because there is nobody listening. m_outError.println( "Exiting JVM..." ); stopImmediate( 1 ); } else if ( ( e instanceof BindException ) || ( ( eMessage != null ) && ( ( eMessage.indexOf( "errno: 48" ) >= 0 ) || ( eMessage.indexOf( "Address already in use" ) >= 0 ) ) || ( eMessage.indexOf( "Unrecognized Windows Sockets error: 0: JVM_Bind" ) >= 0 ) ) ) /* This message is caused by a JVM Bug: http://bugs.sun.com/view_bug.do?bug_id=6965962 */ { // Most Java implementations throw a BindException when the port is in use, // but FreeBSD throws a SocketException with a specific message. // This happens if the local port is already in use. In this case, we want // to loop and try again. if ( m_debug ) { m_outDebug.println( getRes().getString( "Unable to open socket to Wrapper from port {0}, already in use.", new Integer( tryPort ) ) ); } if ( fixedPort ) { // The last port checked was the fixed port, switch to the dynamic range. tryPort = m_jvmPortMin; fixedPort = false; } else { tryPort++; } // Keep this exception around in case we need to log it. if ( causeException == null ) { causeException = e; } } else { // Unexpected exception. m_outError.println( getRes().getString( "Unexpected exception opening backend socket: {0}", e ) ); m_backendSocket = null; return; } } catch ( IOException e ) { m_outError.println( getRes().getString( "Unable to open backend socket: {0}", e ) ); m_backendSocket = null; return; } } while ( tryPort <= m_jvmPortMax ); if ( connected ) { if ( ( m_jvmPort >= 0 ) && ( m_jvmPort != tryPort ) ) { m_outInfo.println(getRes().getString( "Port {0} already in use, using port {1} instead.", new Integer( m_jvmPort ), new Integer( tryPort ) ) ); } } else { if ( m_jvmPortMax > m_jvmPortMin ) { m_outError.println( getRes().getString( "Failed to connect to the Wrapper at port {0} by binding to any ports in the range {1} to {2}. Cause: {3}", new Integer( m_port ), new Integer( m_jvmPortMin ), new Integer( m_jvmPortMax ), causeException ) ); } else { m_outError.println(getRes().getString( "Failed to connect to the Wrapper at port {0} by binding to port {1}. Cause: {2}", new Integer( m_port ), new Integer( m_jvmPortMin ), causeException ) ); } // This is fatal because there is nobody listening. m_outError.println( getRes().getString( "Exiting JVM..." ) ); stopImmediate( 1 ); } // Now that we have a connected socket, continue on to configure it. try { // Turn on the TCP_NODELAY flag. This is very important for speed!! m_backendSocket.setTcpNoDelay( true ); // If configured, set the SO_TIMEOUT for the socket (max block time) if ( m_soTimeout >= 0 ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Setting backend socket SO_TIMEOUT to {0}ms from {1}ms.", new Integer( m_soTimeout ), new Integer( m_backendSocket.getSoTimeout() ) ) ); } m_backendSocket.setSoTimeout( m_soTimeout ); } m_backendOS = m_backendSocket.getOutputStream(); m_backendIS = m_backendSocket.getInputStream(); } catch ( IOException e ) { m_outError.println( e ); closeBackend(); return; } m_backendConnected = true; } private static synchronized void openBackendPipe() { String s; if (WrapperManager.isWindows()) { s = "\\\\.\\pipe\\wrapper-" + WrapperManager.getWrapperPID() + "-" + WrapperManager.getJVMId(); } else { s = "/tmp/wrapper-" + WrapperManager.getWrapperPID() + "-" + WrapperManager.getJVMId(); } try { m_backendIS = new FileInputStream( new File( s + "-out") ); m_backendOS = new FileOutputStream( new File( s + "-in" ) ); } catch ( IOException e ) { m_outInfo.println( "write error " + e ); e.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } m_backendConnected = true; } private static synchronized void openBackend() { m_backendConnected = false; if ( m_backendType == BACKEND_TYPE_PIPE ) { openBackendPipe(); } else { openBackendSocket(); } if ( !m_backendConnected ) { return; } // The backend is open. // Send the key back to the wrapper so that the wrapper can feel safe // that it is talking to the correct JVM sendCommand( WRAPPER_MSG_KEY, m_key ); // If there is a stop pending then send it immediately now. if ( m_pendingStopMessage != null ) { m_outDebug.println( getRes().getString( "Resend pending packet {0} : {1}", getPacketCodeName( WRAPPER_MSG_STOP ), m_pendingStopMessage ) ); sendCommand( WRAPPER_MSG_STOP, m_pendingStopMessage ); m_pendingStopMessage = null; } } private static synchronized void closeBackend() { if ( m_backendConnected ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Closing backend connection." ) ); } // To avoid the case where a child process is launched by we fail to notify the Wrapper, // we need to wait until there are no longer any child processes in the process of being launched. long start = System.currentTimeMillis(); while ( m_runningExecs > 0 ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Waiting for {0} threads to fininish launching child processes...", new Integer( m_runningExecs ) ) ); } try { WrapperManager.class.wait( 1000 ); } catch ( InterruptedException e ) { } if ( System.currentTimeMillis() - start > 30000 ) { m_outError.println( getRes().getString( "Timed out waiting for {0} threads to fininish launching child processes.", new Integer( m_runningExecs ) ) ); break; } } // Clear the connected flag first so other threads will recognize that we // are closing correctly. m_backendConnected = false; // On HP platforms, an attempt to close a socket while a read is blocking will // cause the close to block until the read completes. To avoid this, send an // interrupt to the communications runner to abort any existing reads. Thread commRunner = m_commRunner; if ( commRunner != null ) { try { commRunner.interrupt(); } catch ( SecurityException e ) { m_outError.println( getRes().getString( "Failed to interrupt communications thread: {0}", e.getMessage() ) ); } } } if ( m_backendOS != null ) { try { m_backendOS.close(); } catch ( IOException e ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Unable to close backend output stream: {0}", e.toString() ) ); } } m_backendOS = null; } if ( m_backendIS != null ) { // Closing m_backendIS here will block on some platforms. Let the Wrapper end it cleanup. m_backendIS = null; } if ( m_backendSocket != null ) { try { m_backendSocket.close(); } catch ( IOException e ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Unable to close backend socket: {0}", e.toString() ) ); } } m_backendSocket = null; } } private static String getPacketCodeName( byte code ) { String name; switch ( code ) { case WRAPPER_MSG_START: name ="START"; break; case WRAPPER_MSG_STOP: name ="STOP"; break; case WRAPPER_MSG_RESTART: name ="RESTART"; break; case WRAPPER_MSG_PING: name ="PING"; break; case WRAPPER_MSG_STOP_PENDING: name ="STOP_PENDING"; break; case WRAPPER_MSG_START_PENDING: name ="START_PENDING"; break; case WRAPPER_MSG_STARTED: name ="STARTED"; break; case WRAPPER_MSG_STOPPED: name ="STOPPED"; break; case WRAPPER_MSG_KEY: name ="KEY"; break; case WRAPPER_MSG_BADKEY: name ="BADKEY"; break; case WRAPPER_MSG_LOW_LOG_LEVEL: name ="LOW_LOG_LEVEL"; break; case WRAPPER_MSG_PING_TIMEOUT: /* No longer used. */ name ="PING_TIMEOUT"; break; case WRAPPER_MSG_SERVICE_CONTROL_CODE: name ="SERVICE_CONTROL_CODE"; break; case WRAPPER_MSG_PROPERTIES: name ="PROPERTIES"; break; case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_DEBUG: name ="LOG(DEBUG)"; break; case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_INFO: name ="LOG(INFO)"; break; case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_STATUS: name ="LOG(STATUS)"; break; case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_WARN: name ="LOG(WARN)"; break; case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_ERROR: name ="LOG(ERROR)"; break; case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_FATAL: name ="LOG(FATAL)"; break; case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_ADVICE: name ="LOG(ADVICE)"; break; case WRAPPER_MSG_LOG + WRAPPER_LOG_LEVEL_NOTICE: name ="LOG(NOTICE)"; break; case WRAPPER_MSG_CHILD_LAUNCH: name ="CHILD_LAUNCH"; break; case WRAPPER_MSG_CHILD_TERM: name ="CHILD_TERM"; break; case WRAPPER_MSG_LOGFILE: name ="LOGFILE"; break; case WRAPPER_MSG_CHECK_DEADLOCK: name ="CHECK_DEADLOCK"; break; case WRAPPER_MSG_DEADLOCK: name ="DEADLOCK"; break; case WRAPPER_MSG_APPEAR_ORPHAN: /* No longer used. */ name ="APPEAR_ORPHAN"; break; case WRAPPER_MSG_PAUSE: name ="PAUSE"; break; case WRAPPER_MSG_RESUME: name ="RESUME"; break; case WRAPPER_MSG_GC: name ="GC"; break; case WRAPPER_MSG_FIRE_USER_EVENT: name ="FIRE_USER_EVENT"; break; default: name = "UNKNOWN(" + code + ")"; break; } return name; } /** * Send a command to the Wrapper. * * @param code Command to send. * @param message Message to send with the command. */ private static synchronized void sendCommand( byte code, String message ) { if ( m_debug ) { // We want to show these messages even if we are pretending to be hung. if ( ( code == WRAPPER_MSG_PING ) && ( message.startsWith( "silent" ) ) ) { // m_outDebug.println( "Send silent ping packet." ); } else if ( !m_backendConnected ) { m_outDebug.println( getRes().getString( "Backend not connected, not sending packet {0} : {1}", getPacketCodeName( code ), message ) ); if ( code == WRAPPER_MSG_STOP ) { // Store this message so we can send it later if and when we connect. m_pendingStopMessage = message; } } else { m_outDebug.println( getRes().getString( "Send a packet {0} : {1}", getPacketCodeName( code ) , message ) ); } } boolean sentCommand = false; if ( m_appearHung ) { // The WrapperManager is attempting to make the JVM appear hung, so do nothing } else { if ( ( code == WRAPPER_MSG_START_PENDING ) || ( code == WRAPPER_MSG_STARTED ) ) { // Set the last ping time so that the startup process does not time out // thinking that the JVM has not received a Ping for too long. m_lastPingTicks = getTicks(); } // If the backend is open, then send the command, otherwise just throw it away. if ( m_backendConnected ) { try { // It is possible that a logged message is quite large. Expand the size // of the command buffer if necessary so that it can be included. This // means that the command buffer will be the size of the largest message. byte[] messageBytes = message.getBytes(); if ( m_commandBuffer.length < messageBytes.length + 2 ) { m_commandBuffer = new byte[messageBytes.length + 2]; } // Writing the bytes one by one was sometimes causing the first byte to be lost. // Try to work around this problem by creating a buffer and sending the whole lot // at once. m_commandBuffer[0] = code; System.arraycopy( messageBytes, 0, m_commandBuffer, 1, messageBytes.length ); int len = messageBytes.length + 2; m_commandBuffer[len - 1] = 0; m_backendOS.write( m_commandBuffer, 0, len ); m_backendOS.flush(); sentCommand = true; } catch ( IOException e ) { m_outError.println( e ); e.printStackTrace( m_outError ); closeBackend(); } } } if ( !sentCommand ) { // We failed to send a command. Some commands require that we log it as it could cause later problems. switch ( code ) { case WRAPPER_MSG_CHILD_LAUNCH: m_outError.println( getRes().getString( "Failed to notify the Wrapper process that child with PID={0} was launched. The Wrapper will not be able to make sure it is terminated when the Java process exits.", message ) ); break; case WRAPPER_MSG_CHILD_TERM: if ( m_debug ) { m_outDebug.println( getRes().getString( "Failed to notify the Wrapper process that child with PID={0} completed. The Wrapper will recover on its own.", message ) ); } break; default: break; } } } /** * Loop reading packets from the native side of the Wrapper until the * connection is closed or the WrapperManager class is disposed. * Each packet consists of a packet code followed by a null terminated * string up to 256 characters in length. If the entire packet has not * yet been received, then it must not be read until the complete packet * has arived. */ private static byte[] m_backendReadBuffer = new byte[256]; private static void handleBackend() { WrapperPingEvent pingEvent = new WrapperPingEvent(); try { if ( m_debug ) { m_outDebug.println( getRes().getString( "handleBackend()" ) ); } DataInputStream is = new DataInputStream( m_backendIS ); while ( !m_disposed ) { try { // A Packet code must exist. byte code = is.readByte(); // Always read from the buffer until a null '\0' is encountered. // A multi-byte string will never have a 0 as part of another character so this should be safe for all encodings. byte b; int i = 0; do { b = is.readByte(); if ( b != 0 ) { if ( i >= m_backendReadBuffer.length ) { byte[] tmp = m_backendReadBuffer; m_backendReadBuffer = new byte[tmp.length + 256]; System.arraycopy( tmp, 0, m_backendReadBuffer, 0, tmp.length ); } m_backendReadBuffer[i] = b; i++; } } while ( b != 0 ); // The message should be multi-byte string in the system encoding. String msg = new String( m_backendReadBuffer, 0, i ); if ( m_appearHung ) { // The WrapperManager is attempting to make the JVM appear hung, // so ignore all incoming requests } else { if ( m_debug ) { String logMsg; if ( code == WRAPPER_MSG_PROPERTIES ) { // The property values are very large and distracting in the log. // Plus if any triggers are defined, then logging them will fire // the trigger. logMsg = getRes().getString( "(Property Values, Size={0})", Integer.toString( i ) ); } else { logMsg = msg; } // Don't log silent pings. if ( ( code == WRAPPER_MSG_PING ) && ( msg.startsWith( "silent" ) ) ) { //m_outDebug.println( "Received silent ping packet." ); } else { m_outDebug.println( getRes().getString( "Received a packet {0} : {1}", getPacketCodeName( code ) , logMsg ) ); } } if ( m_slowSeconds > 0 ) { // We have been asked to be sluggish in the JVM's response. if ( m_debug ) { m_outDebug.println( getRes().getString( " Delay packet processing by {0} seconds.", new Integer( m_slowSeconds ) ) ); } try { Thread.sleep( m_slowSeconds * 1000 ); } catch ( InterruptedException e ) { } } // Ok, we got a packet. Do something with it. switch( code ) { case WRAPPER_MSG_START: // Don't start if we are already starting to stop. if ( m_stoppingInit) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Java stop initiated. Skipping application startup." ) ); } } else { startInner( false ); } break; case WRAPPER_MSG_STOP: // Don't do anything if we are already stopping if ( !m_stopping ) { privilegedStopInner( 0 ); // Should never get back here. } break; case WRAPPER_MSG_PING: m_lastPingTicks = getTicks(); sendCommand( WRAPPER_MSG_PING, msg ); if ( m_produceCoreEvents ) { fireWrapperEvent( pingEvent ); } break; case WRAPPER_MSG_CHECK_DEADLOCK: boolean deadLocked = checkDeadlocks(); if ( deadLocked ) { sendCommand( WRAPPER_MSG_DEADLOCK, "deadLock" ); } break; case WRAPPER_MSG_BADKEY: // The key sent to the wrapper was incorrect. We need to shutdown. m_outError.println( getRes().getString("Authorization key rejected by Wrapper." ) ); m_outError.println( getRes().getString( "Exiting JVM..." ) ); closeBackend(); privilegedStopInner( 1 ); break; case WRAPPER_MSG_LOW_LOG_LEVEL: try { m_lowLogLevel = Integer.parseInt( msg ); m_debug = ( m_lowLogLevel <= WRAPPER_LOG_LEVEL_DEBUG ); if ( m_debug ) { m_outDebug.println( getRes().getString( "LowLogLevel from Wrapper is {0}", new Integer( m_lowLogLevel ) ) ); } } catch ( NumberFormatException e ) { m_outError.println( getRes().getString( "Encountered an Illegal LowLogLevel from the Wrapper: {0}", msg ) ); } break; case WRAPPER_MSG_PING_TIMEOUT: /* No longer used. This is still here in case a mix of versions are used. */ break; case WRAPPER_MSG_SERVICE_CONTROL_CODE: try { int serviceControlCode = Integer.parseInt( msg ); if ( m_debug ) { m_outDebug.println( getRes().getString( "ServiceControlCode from Wrapper with code {0}", new Integer( serviceControlCode ) ) ); } WrapperServiceControlEvent event = new WrapperServiceControlEvent( serviceControlCode ); fireWrapperEvent( event ); } catch ( NumberFormatException e ) { m_outError.println( getRes().getString( "Encountered an Illegal ServiceControlCode from the Wrapper: {0}", msg ) ); } break; case WRAPPER_MSG_PAUSE: try { int actionSourceCode = Integer.parseInt( msg ); if ( m_debug ) { m_outDebug.println( getRes().getString( "Pause from Wrapper with action source: {0}", WrapperServicePauseEvent.getSourceCodeName( actionSourceCode ) ) ); } WrapperServicePauseEvent event = new WrapperServicePauseEvent( actionSourceCode ); fireWrapperEvent( event ); } catch ( NumberFormatException e ) { m_outError.println( getRes().getString( "Encountered an Illegal action source code from the Wrapper: {0}", msg ) ); } break; case WRAPPER_MSG_RESUME: try { int actionSourceCode = Integer.parseInt( msg ); if ( m_debug ) { m_outDebug.println( getRes().getString("Resume from Wrapper with action source: {0}", WrapperServiceResumeEvent.getSourceCodeName( actionSourceCode ) ) ); } WrapperServiceResumeEvent event = new WrapperServiceResumeEvent( actionSourceCode ); fireWrapperEvent( event ); } catch ( NumberFormatException e ) { m_outError.println( getRes().getString( "Encountered an Illegal action source code from the Wrapper: {0}", msg ) ); } break; case WRAPPER_MSG_GC: try { int actionSourceCode = Integer.parseInt( msg ); if ( m_debug ) { m_outDebug.println( getRes().getString( "Garbage Collection request from Wrapper with action source: {0}", WrapperServiceActionEvent.getSourceCodeName( actionSourceCode ) ) ); } System.gc(); } catch ( NumberFormatException e ) { m_outError.println( getRes().getString( "Encountered an Illegal action source code from the Wrapper: {0}", msg ) ); } break; case WRAPPER_MSG_PROPERTIES: readProperties( msg ); break; case WRAPPER_MSG_LOGFILE: m_logFile = new File( msg ); WrapperLogFileChangedEvent event = new WrapperLogFileChangedEvent( m_logFile ); fireWrapperEvent( event ); break; default: // Ignore unknown messages m_outInfo.println( getRes().getString( "Wrapper code received an unknown packet type: {0}", new Integer( code ) ) ); break; } } } catch ( SocketTimeoutException e ) { if ( m_debug ) { m_outDebug.println( getRes().getString( "Backend socket timed out. Attempting to continue. (SO_TIMEOUT={0}ms.)", new Integer( m_backendSocket.getSoTimeout() ) ) ); } } } if ( m_debug ) { m_outDebug.println( getRes().getString( "Backend handler loop completed. Disposed: {0}", ( m_disposed ? "True" : "False" ) ) ); } return; } catch ( SocketException e ) { if ( m_debug ) { if ( m_backendSocket == null ) { // This error happens if the socket is closed while reading: // java.net.SocketException: Descriptor not a socket: JVM_recv in socket // input stream read m_outDebug.println( getRes().getString( "Closed backend socket (Normal): {0}", e ) ); } else { m_outDebug.println( getRes().getString( "Closed backend socket: {0}", e ) ); } } return; } catch ( IOException e ) { // This means that the connection was closed. Allow this to return. if ( m_debug ) { m_outDebug.println( getRes().getString( "Closed backend (Normal): {0}", e ) ); } return; } } /** * Starts up the thread to handle backend communications. * * If the Wrapper did not launch the JVM then the internal state * will be set to started to allow the application startup to continue. */ private static void startRunner() { if ( isControlledByNativeWrapper() ) { if ( m_commRunner == null ) { // Create and launch a new thread to manage this connection m_commRunner = new Thread( m_instance, WRAPPER_CONNECTION_THREAD_NAME ); m_commRunner.setDaemon( true ); m_commRunner.start(); } // Wait to give the runner a chance to connect. synchronized( WrapperManager.class ) { while ( !m_commRunnerStarted ) { try { WrapperManager.class.wait( 100 ); } catch ( InterruptedException e ) { } } } } else { // Immediately mark the runner as started as it will never be used. synchronized( WrapperManager.class ) { m_commRunnerStarted = true; WrapperManager.class.notifyAll(); } } } /*--------------------------------------------------------------- * Runnable Methods *-------------------------------------------------------------*/ /** * The main comm runner thread. * This will only be called when the Wrapper is controlling the JVM. */ public void run() { // Make sure that no other threads call this method. if ( Thread.currentThread() != m_commRunner ) { throw new IllegalStateException( getRes().getString( "Only the communications runner thread is allowed to call this method." ) ); } if ( m_debug ) { m_outDebug.println( getRes().getString( "Communications runner thread started." ) ); } // This thread needs to have a very high priority so that it never // gets put behind other threads. Thread.currentThread().setPriority( Thread.MAX_PRIORITY ); // Initialize the last ping tick count. m_lastPingTicks = getTicks(); try { openBackend(); // After the socket has been opened the first time, mark the thread as // started. This must be done here to make sure that exits work correctly // when called on startup. if ( !m_commRunnerStarted ) { synchronized( WrapperManager.class ) { m_commRunnerStarted = true; WrapperManager.class.notifyAll(); } } if ( m_backendSocket != null || m_backendConnected == true) { handleBackend(); } else { // Failed, so wait for just a moment try { Thread.sleep( 100 ); } catch ( InterruptedException e ) { } } } catch ( ThreadDeath td ) { m_outError.println( getRes().getString( "Server daemon killed" ) ); } catch ( Throwable t ) { if ( !isShuttingDown() ) { // Show a stack trace here because this is fairly critical m_outError.println( getRes().getString( "Server daemon died!" ) ); t.printStackTrace( m_outError ); } else { if ( m_debug ) { m_outDebug.println( getRes().getString( "Server daemon died!" ) ); t.printStackTrace( m_outDebug ); } } } finally { if ( m_debug ) { m_outDebug.println( getRes().getString( "Returned from backend handler." ) ); } // Always close the backend here. closeBackend(); if ( !isShuttingDown() ) { if ( m_detachStarted && m_started ) { // This and all further output will not be visible anywhere as the Wrapper is now gone. m_outInfo.println( getRes().getString( "The backend was closed as expected." ) ); if ( isNativeLibraryOk() ) { nativeRedirectPipes(); } else { m_outError.println( getRes().getString( "Failed to redirect stdout and stderr before the Wrapper exits.\nOutput from the JVM may block.\nPlease make sure the native library has been properly initialized.")); } } else { m_outError.println( getRes().getString( "The backend was closed unexpectedly. Restart to resync with the Wrapper." ) ); restart(); // Will not get here. } } } // Make sure that noone is ever left waiting for this thread to start. synchronized( WrapperManager.class ) { if ( !m_commRunnerStarted ) { m_commRunnerStarted = true; WrapperManager.class.notifyAll(); } } if ( m_debug ) { m_outDebug.println( getRes().getString( "Server daemon shut down" ) ); } } /*--------------------------------------------------------------- * Inner Classes *-------------------------------------------------------------*/ /** * Mapping between WrapperEventListeners and their registered masks. * This is necessary to support the case where the same listener is * registered more than once. It also makes it possible to reference * an array of these mappings without synchronization. */ private static class WrapperEventListenerMask { private WrapperEventListener m_listener; private long m_mask; } private static class WrapperTickEventImpl extends WrapperTickEvent { private int m_ticks; private int m_tickOffset; /** * Returns the tick count at the point the event is fired. * * @return The tick count at the point the event is fired. */ public int getTicks() { return m_ticks; } /** * Returns the offset between the tick count used by the Wrapper for time * keeping and the tick count generated directly from the system time. * * This will be 0 in most cases. But will be a positive value if the * system time is ever set back for any reason. It will be a negative * value if the system time is set forward or if the system is under * heavy load. If the wrapper.use_system_time property is set to TRUE * then the Wrapper will be using the system tick count for internal * timing and this value will always be 0. * * @return The tick count offset. */ public int getTickOffset() { return m_tickOffset; } } /** * When the JVM is being controlled by the Wrapper, stdin can not be used * as it is undefined. This class makes it possible to provide the user * application with a descriptive error message if System.in is accessed. */ private static class WrapperInputStream extends InputStream { /** * This method will always throw an IOException as the read method is * not valid. */ public int read() throws IOException { m_outInfo.println( getRes().getString( "WARNING - System.in has been disabled by the wrapper.disable_console_input property. Calls will block indefinitely." ) ); // Go into a loop that will never return. while ( true ) { synchronized( this ) { try { this.wait(); } catch ( InterruptedException e ) { // Ignore. } } } } } /** * Scans the JVM for deadlocked threads. *

* Standard Edition feature. * * @see #isStandardEdition() * @since Wrapper 3.5.0 */ private static boolean checkDeadlocks() throws WrapperLicenseError { if ( isStandardEdition() ) { boolean result = false; if ( isNativeLibraryOk() ) { result = nativeCheckDeadLocks(); } else { if ( m_debug ) { m_outDebug.println( getRes().getString( "Deadlock check skipped. Native call unavailable." ) ); } result = false; } return result; } else { return false; } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperPrintStream.java100644 0 0 4567 12440202301 25050 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.PrintStream; /** * Not all methods are currently overridden as this is an internal class. */ final class WrapperPrintStream extends PrintStream { private String m_header; WrapperPrintStream( PrintStream parent, String header ) { super( parent ); m_header = header; } /** * Terminate the current line by writing the line separator string. The * line separator string is defined by the system property * line.separator, and is not necessarily a single newline * character ('\n'). */ public void println() { super.println( m_header ); } /** * Print a String and then terminate the line. This method behaves as * though it invokes {@link #print(String)} and then * {@link #println()}. * * @param x The String to be printed. */ public void println( String x ) { if ( x.indexOf( "\n" ) >= 0 ) { String[] lines = x.split( "[\n]", -1 ); StringBuffer sb = new StringBuffer(); for ( int i = 0; i < lines.length; i++ ) { if ( i > 0 ) { sb.append( "\n" ); } sb.append( m_header ); sb.append( lines[i] ); } super.println( sb.toString() ); } else { super.println( m_header + x ); } } /** * Print an Object and then terminate the line. This method behaves as * though it invokes {@link #print(Object)} and then * {@link #println()}. * * @param x The Object to be printed. */ public void println( Object x ) { if ( x == null ) { println( "null" ); } else { println( x.toString() ); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperProcess.java100644 0 0 20536 12440202301 24230 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; /** * A WrapperProcess is returned by a call to WrapperManager.exec and can * be used to reference the new child process after it was launched. * * @author Leif Mortenson * @since Wrapper 3.4.0 */ public class WrapperProcess { private WrapperProcessOutputStream m_wpis; private WrapperProcessInputStream m_wpos; private WrapperProcessInputStream m_wpes; /* The PID of the process. */ private int m_pid; private int m_exitcode; private boolean m_isDetached; private int m_softShutdownTimeout; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * The default constructor */ private WrapperProcess() { m_exitcode = Integer.MIN_VALUE; } /*--------------------------------------------------------------- * Native Methods *-------------------------------------------------------------*/ private native boolean nativeIsAlive(); private native void nativeDestroy(); private native void nativeExitValue(); private native void nativeWaitFor(); /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Finalize method. */ protected void finalize() throws Throwable { try { //System.out.println( m_pid + " finalized"); m_wpes.close(); m_wpis.close(); m_wpos.close(); } finally { super.finalize(); } } /** * Returns the PID of the process. * * @return The PID of the process. */ public int getPID() { return m_pid; } /** * Gets the input stream of the subprocess. The stream obtains data piped * from the standard output stream of the process represented by this * WrapperProcess object. *

* This is an alias of the getStdOut() method. *

* Implementation note: It is a good idea for the input stream to be * buffered. * * @return The input stream connected to the normal output of the * subprocess. * * @throws IOException If we are unable to access the stream. */ public InputStream getInputStream() throws IOException { return m_wpos; } /** * Gets the input stream of the subprocess. The stream obtains data piped * from the standard output stream of the process represented by this * WrapperProcess object. *

* This is an alias of the getInputStream() method. *

* Implementation note: It is a good idea for the input stream to be * buffered. * * @return The input stream connected to the normal output of the * subprocess. * * @throws IOException If we are unable to access the stream. */ public InputStream getStdOut() throws IOException { return m_wpos; } /** * Gets the error stream of the subprocess. The stream obtains data piped * from the error output stream of the process represented by this * WrapperProcess object. *

* This is an alias of the getStdErr() method. *

* Implementation note: It is a good idea for the input stream to be * buffered. * * @return The input stream connected to the error stream of the * subprocess. * * @throws IOException If we are unable to access the stream. */ public InputStream getErrorStream() throws IOException { return m_wpes; } /** * Gets the error stream of the subprocess. The stream obtains data piped * from the error output stream of the process represented by this * WrapperProcess object. *

* This is an alias of the getErrorStream() method. *

* Implementation note: It is a good idea for the input stream to be * buffered. * * @return The input stream connected to the error stream of the * subprocess. * * @throws IOException If we are unable to access the stream. */ public InputStream getStdErr() throws IOException { return m_wpes; } /** * Gets the output stream of the subprocess. Output to the stream is piped * into the standard input stream of the process represented by this * WrapperProcess object. *

* This is an alias of the getStdIn() method. *

* Implementation note: It is a good idea for the output stream to be * buffered. * * @return The output stream connected to the normal input of the * subprocess. * * @throws IOException If we are unable to access the stream. */ public OutputStream getOutputStream() throws IOException { return m_wpis; } /** * Gets the output stream of the subprocess. Output to the stream is piped * into the standard input stream of the process represented by this * WrapperProcess object. *

* This is an alias of the getOutputStream() method. *

* Implementation note: It is a good idea for the output stream to be * buffered. * * @return The output stream connected to the normal input of the * subprocess. * * @throws IOException If we are unable to access the stream. */ public OutputStream getStdIn() throws IOException { return m_wpis; } /** * Causes the current thread to wait, if necessary, until the process * represented by this Process object has terminated. This method returns * immediately if the subprocess has already terminated. If the subprocess * has not yet terminated, the calling thread will be blocked until the * subprocess exits. * * @return The exit value of the process. By convention, 0 indicates normal * termination. * * @throws InterruptedException If the current thread is interrupted by * another thread while it is waiting, then * the wait is ended and an * InterruptedException is thrown. */ public int waitFor() throws InterruptedException { if ( m_exitcode == Integer.MIN_VALUE ) { nativeWaitFor(); } return m_exitcode; } /** * Returns the exit value for the subprocess. * * @return The exit value of the subprocess represented by this * WrapperProcess object. By convention, the value 0 * indicates normal termination. * * @throws IllegalThreadStateException if the process is still alive * and has not yet teminated. */ public int exitValue() throws IllegalThreadStateException { if ( m_exitcode == Integer.MIN_VALUE ) { nativeExitValue(); } return m_exitcode; } /** * Returns true if the process is still alive. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. * @return True if the process is alive, false if it has terminated. */ public boolean isAlive() { return nativeIsAlive(); } /** * Kills the subprocess. The subprocess represented by this Process object * is forcibly terminated if it is still running. * * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. */ public void destroy() { nativeDestroy(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperProcessConfig.java100644 0 0 37204 12440202301 25356 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.Map; import java.util.HashMap; import org.tanukisoftware.wrapper.WrapperLicenseError; /** * With WrapperProcessConfig Class the startup configuration for the Process * can be passed to the WrapperManager.exec methods. The configuration makes * it possible to control the way the OS spawns the child process, specify * environment variables, working directory, and how the Wrapper should handle * process when the JVM exits. Please review each of the methods a more * detailed explanation of how they work. *

* The setter methods are designed to be optionally be chained as follows: *

 * WrapperProcess proc = WrapperManager.exec( "command", new WrapperProcessConfig().setDetached( true ).setStartType( WrapperProcessConfig.POSIX_SPAWN ) );
 * 
* * @author Christian Mueller * @since Wrapper 3.4.0 */ public final class WrapperProcessConfig { public static final int POSIX_SPAWN = 1; public static final int FORK_EXEC = 2; public static final int VFORK_EXEC = 3; public static final int DYNAMIC = 4; private boolean m_isDetached; private boolean m_isInteractive; private File m_defdir; private int m_startType; private Map m_environment; private int m_softShutdownTimeout; private native String[] nativeGetEnv(); private static native boolean isSupportedNative( int startType ); /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a default configuration. * * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or if the native * library has not been loaded. */ public WrapperProcessConfig() { WrapperManager.assertProfessionalEdition(); m_isDetached = false; m_defdir = null; m_startType = DYNAMIC; m_environment = null; m_softShutdownTimeout = 5; m_isInteractive = false; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Indicates whether the specified start type is supported on the current * plattform. * * @param startType The start type to test. * * @return true if supported, false otherwise. On Windows, this method always returns * true. * * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or if the native * library has not been loaded. * @throws IllegalArgumentException If the startType is invalid. */ public static boolean isSupported( int startType ) throws WrapperLicenseError, IllegalArgumentException { WrapperManager.assertProfessionalEdition(); verifyStartType( startType ); if ( WrapperManager.isNativeLibraryOk() ) { return isSupportedNative( startType ); } else { return false; } } /** * Returns the detached flag. * * @return The detached flag. */ public boolean isDetached() { return m_isDetached; } /** * Sets the detached flag. This makes it possible to control whether or * not the Wrapper will terminate any child processes launched by a JVM * when that JVM exits or crashes. * * @param detached If false the Wrapper will remember that the process was * launched and then make sure that it is terminated when * the JVM exits. * * @return This configration to allow chaining. */ public WrapperProcessConfig setDetached( boolean detached ) { m_isDetached = detached; return this; } /** * Returns the start type. * * @return The start type. */ public int getStartType() { return m_startType; } /** * Sets the start type. *

* The start type is used to control how the subprocess will be started by * the OS. This property has no effect on Windows. *

    *
  • FORK_EXEC - The most common UNIX/LINUX way to create a child * process. On some operating systems (esp. Solaris) this call causes * results in the operating system momentarily duplicating the JVM's * memory before launching the child process. If the JVM is large then * this can result in system level memory errors that can cause the * child process to fail or even the JVM to crash.
  • *
  • VFORK_EXEC - The vfork function differs from fork only in that the * child process can share code and data with the parent process. This * speeds cloning activity significantly. Care is taken in this * implementation to avoid the kind of integrety problems that are * possible with this method. On some systems, vfork is the same as * fork.
  • *
  • POSIX_SPAWN - The process will be spawned in such a way that no * memory duplication takes place. This makes it possible to spawn * child processes when the JVM is very large on Solaris systems. * (See http://www.opengroup.org/onlinepubs/009695399/functions/posix_spawn.html) * This is available on LINUX, SOLARIS (10+), AIX, z/OS and MACOS. * It will not be possible to set the working directory when using * this start type.
  • *
  • DYNAMIC - The ideal forking method will be used for the current * platform. * It will not be possible to set the working directory when using * this start type as the start type used on some platforms does not * support setting a working directory.
  • *
* * @param startType The start type to use when launching the child process. * * @return This configration to allow chaining. * * @throws IllegalArgumentException If the startType is invalid. */ public WrapperProcessConfig setStartType( int startType ) throws IllegalArgumentException { verifyStartType( startType ); m_startType = startType; return this; } /** * Returns the working directory. * * @return The working directory. */ public File getWorkingDirectory() { return m_defdir; } /** * Sets the working directory. * * @param workingDirectory The working directory of the subprocess, or null * if the subprocess should inherit the working * directory of the JVM. * Please note, when using the POSIX_SPAWN or DYNAMIC start * type, it is not possible to set the working * directory. Doing so will result in an error when running exec. * * @return This configration to allow chaining. * * @throws IOException If the specified working directory can not be resolved. */ public WrapperProcessConfig setWorkingDirectory( File workingDirectory ) throws IOException { if ( workingDirectory != null ) { if ( !workingDirectory.exists() ) { throw new IllegalArgumentException( WrapperManager.getRes().getString( "Working directory does not exist." ) ); } else if ( !workingDirectory.isDirectory() ) { throw new IllegalArgumentException( WrapperManager.getRes().getString( "Must be a directory." ) ); } } m_defdir = workingDirectory.getCanonicalFile(); return this; } /** * Returns a Map containing the environment which will be used to launch * the child process. *

* If this Map is modified those changes will be reflected when the process * is launched. Alternately, the environment can be set with the * setEnvironment method. Clearing the Map will result in an empty * environment being used. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. */ public Map getEnvironment() throws WrapperLicenseError { if ( m_environment == null ) { m_environment = getDefaultEnvironment(); } return m_environment; } /** * Sets the environment for the child process. * * @param environment A Map containing the environment to use when launching * the process. Passing in an empty Map will result in * an empty Environment being used. A null native will * cause the process to be launched using the same * environment as the JVM. * * @return This configration to allow chaining. * * @throws IllegalArgumentException If any of the names or values are not * Strings or if a name is empty. */ public WrapperProcessConfig setEnvironment( Map environment ) { if ( environment != null ) { for ( Iterator iter = environment.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry)iter.next(); Object key = entry.getKey(); if ( !( key instanceof String ) ) { throw new IllegalArgumentException( WrapperManager.getRes().getString( "Map entry names must be Strings." ) ); } else if ( ( (String)key ).length() <= 0 ) { throw new IllegalArgumentException( WrapperManager.getRes().getString( "Map entry names must not be empty Strings." ) ); } else if ( ( (String)key ).indexOf( '=' ) != -1 ) { throw new IllegalArgumentException( WrapperManager.getRes().getString( "Map entry names must not contain an equal sign (''='')." ) ); } Object value = entry.getKey(); if ( !( value instanceof String ) ) { throw new IllegalArgumentException( WrapperManager.getRes().getString( "Map entry values must be Strings." ) ); } } } m_environment = environment; return this; } /** * Sets the timeout for the soft shtudown in seconds. * When WrapperProcess.destroy() is called the wrapper will first try to * stop the application softly giving it time to stop itself properly. * If the specified timeout however ellapsed, the Child Process will be * terminated by hard. * If 0 was specified, the wrapper will instantly force the termination. * If -1 was specified, the wrapper will wait indefinitely for the child * to perform the stop. * The default value of this property is 5 - giving a process 5 sec to * react on the shutdown request. * * @param softShutdownTimeout The max timeout for an application to stop, before * killing forcibly * * @return This configration to allow chaining. * * @throws IllegalArgumentException If the value of the specified timeout is invalid. */ public WrapperProcessConfig setSoftShutdownTimeout( int softShutdownTimeout ) throws IOException { if ( softShutdownTimeout < -1 ) { throw new IllegalArgumentException( WrapperManager.getRes().getString( "{0} is not a valid value for a timeout.", new Integer ( softShutdownTimeout ) ) ); } m_softShutdownTimeout = softShutdownTimeout; return this; } /*--------------------------------------------------------------- * Private Methods *-------------------------------------------------------------*/ /** * Makes sure that the specified startType is valid. * * @param startType Start type to test. * * @throws IllegalArgumentException If the startType is invalid. */ private static void verifyStartType( int startType ) throws IllegalArgumentException { switch( startType ) { case POSIX_SPAWN: case VFORK_EXEC: case FORK_EXEC: case DYNAMIC: break; default: throw new IllegalArgumentException( WrapperManager.getRes().getString( "Unknown start type: {0}", new Integer( startType ) ) ); } } /** * Returns a Map containing the environment of the current Java process. */ private Map getDefaultEnvironment() { Map environment = new HashMap(); if ( WrapperManager.isNativeLibraryOk() ) { String[] nativeEnv = nativeGetEnv(); for ( int i = 0; i < nativeEnv.length; i++ ) { int pos = nativeEnv[i].indexOf( '=' ); String name = nativeEnv[i].substring( 0, pos ); String value = nativeEnv[i].substring( pos + 1 ); environment.put( name, value ); } } return environment; } /** * Called by the native code to get the environment. */ private String[] getNativeEnv() { if ( m_environment == null ) { if ( WrapperManager.isNativeLibraryOk() ) { return nativeGetEnv(); } else { return new String[0]; } } else { String[] nativeEnv = new String[ m_environment.size() ]; Iterator iter = m_environment.entrySet().iterator(); int i = 0; while ( iter.hasNext() ) { Map.Entry pairs = (Map.Entry)iter.next(); nativeEnv[ i++ ] = pairs.getKey() + "=" + pairs.getValue(); } return nativeEnv; } } /** * Specifies if the ChildProcesses should be launched * in the current session. * This property only makes sense if the application was * launched as Windows Service under the System User (or any * other user, having SE_TCB_NAME previledge with the OS) * On non-Windows platforms or when launched in Console mode, * the setting will be ignored silently. * * @param isInteractive true to enable the feature. */ public WrapperProcessConfig setCreateForActiveUser( boolean isInteractive ) { if (WrapperManager.isWindows() && WrapperManager.isLaunchedAsService()) { m_isInteractive = true; } else { m_isInteractive = false; } return this; } /** * Tells if the CreateForActiveUser feature was enabled. */ public boolean isCreateForActiveUser() { return m_isInteractive; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperProcessInputStream.java100644 0 0 25132 12440202301 26421 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.IOException; /** * The InputStream Class of a WrapperProcess, representing all the data the * ChildProcess writes to the Wrapper. * * @author Christian Mueller * @since Wrapper 3.4.0 */ public class WrapperProcessInputStream extends InputStream { private long m_ptr; private boolean m_closed; private ByteArrayInputStream m_bais; private volatile boolean m_read; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * This class can only be instantiated by native code. */ private WrapperProcessInputStream() { } /*--------------------------------------------------------------- * Native Methods *-------------------------------------------------------------*/ private native int nativeRead( boolean blocking ); private native void nativeClose(); private native int nativeRead2( byte[] b, int off, int len, boolean blocking ); /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Closes the InputStream * @throws IOException in case of any file errors * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. */ public void close() throws IOException { synchronized( this ) { if ( !m_closed ) { if ( WrapperManager.isNativeLibraryOk() ) { nativeClose(); } m_closed = true; } } } /** * Tests if this input stream supports the mark and reset methods. * * The markSupported method of InputStream returns false. * * @return false. */ public boolean markSupported() { return false; } /** * */ public boolean ready() { synchronized( this ) { if ( !m_closed || ( ( m_bais != null ) && ( m_bais.available() > 0 ) ) ) { return true; } else { return false; } } } /** * Read a character from the Stream and moves the position in the stream * * @return A single character from the stream, or -1 when the end of stream is reached. * * @throws IOException in case the stream has been already closed or any other file error * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. */ public int read() throws IOException { synchronized( this ) { m_read = true; if ( ( !m_closed ) && WrapperManager.isNativeLibraryOk() ) { return nativeRead( true ); } else { if ( m_bais != null ) { return m_bais.read(); } else { throw new IOException( WrapperManager.getRes().getString( "Stream is closed." ) ); } } } } /** * Reads some number of bytes from the input stream and stores them into the buffer array b. * The number of bytes actually read is returned as an integer. This method blocks until input * data is available, end of file is detected, or an exception is thrown. * * If the length of b is zero, then no bytes are read and 0 is returned; otherwise, there is an * attempt to read at least one byte. If no byte is available because the stream is at the end * of the file, the value -1 is returned; otherwise, at least one byte is read and stored into b. * * The first byte read is stored into element b[0], the next one into b[1], and so on. The number * of bytes read is, at most, equal to the length of b. Let k be the number of bytes actually * read; these bytes will be stored in elements b[0] through b[k-1], leaving elements b[k] * through b[b.length-1] unaffected. * * The read(b) method for class InputStream has the same effect as: * * read(b, 0, b.length) * * @param b The buffer into which the data is read. * * @return The total number of bytes read into the buffer, or -1 is there is no more data because * the end of the stream has been reached. * * @throws IOException If the first byte cannot be read for any reason other than the end of the * file, if the input stream has been closed, or if some other I/O error * occurs. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. */ public int read( byte b[ ] ) throws IOException { return read( b, 0, b.length ); } /** * Reads up to len bytes of data from the input stream into an array of bytes. An attempt is made * to read as many as len bytes, but a smaller number may be read. The number of bytes actually * read is returned as an integer. * * This method blocks until input data is available, end of file is detected, or an exception is * thrown. * * If len is zero, then no bytes are read and 0 is returned; otherwise, there is an attempt to * read at least one byte. If no byte is available because the stream is at end of file, the * value -1 is returned; otherwise, at least one byte is read and stored into b. * * The first byte read is stored into element b[off], the next one into b[off+1], and so on. The * number of bytes read is, at most, equal to len. Let k be the number of bytes actually read; * these bytes will be stored in elements b[off] through b[off+k-1], leaving elements b[off+k] * through b[off+len-1] unaffected. * * In every case, elements b[0] through b[off] and elements b[off+len] through b[b.length-1] are * unaffected. * * @param b The buffer into which the data is read. * @param off The start offset in array b from which the data is read. * @param len The maximum number of bytes to read. * * @return The total number of bytes read into the buffer, or -1 is there is no more data because * the end of the stream has been reached. * * @throws IOException If the first byte cannot be read for any reason other than the end of the * file, if the input stream has been closed, or if some other I/O error * occurs. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. */ public int read( byte b[], int off, int len ) throws IOException { int c; synchronized (this) { if ( b == null ) { throw new NullPointerException(); } else if ( ( off < 0 ) || ( len < 0 ) || ( len > b.length - off ) ) { throw new IndexOutOfBoundsException(); } else if ( len == 0 ) { return 0; } if ( !ready() ) { return -1; } m_read = true; if ( ( !m_closed ) && WrapperManager.isNativeLibraryOk() ) { // Attempt to read output in blocking mode. c = nativeRead2( b, off, len, true ); if ( c == -1 ) // a process can terminate only once { // And end of file was encountered. This can happen c = nativeRead2( b, off, len, false ); } } else { if ( m_bais != null ) { c = m_bais.read( b, off, len ); } else { throw new IOException(WrapperManager.getRes().getString( "Stream is closed." ) ); } } return c == 0 ? -1 : c; } } /*--------------------------------------------------------------- * Private Methods *-------------------------------------------------------------*/ /** * This method gets called when a spawned Process has terminated * and the pipe buffer gets read and stored in an byte array. * This way we can close the Filedescriptor and keep the number * of open FDs as small as possible. */ private void readAndCloseOpenFDs() { if ( m_read ) { // Another thread is reading from the stream so we can trust that thread to complete the reads and close on its own. return; } synchronized( this ) { int count; int msg; if ( m_closed || ( !WrapperManager.isNativeLibraryOk() ) ) { return; } try { byte[] buffer = new byte[1024]; count = 0; while ( ( msg = nativeRead( false ) ) != -1 ) { if ( count >= buffer.length ) { byte[] temp = new byte[buffer.length + 1024]; System.arraycopy( buffer, 0, temp, 0, buffer.length ); buffer = temp; } buffer[count++] = (byte)msg; } m_bais = new ByteArrayInputStream( buffer, 0, count ); close(); } catch( IOException ioe ) { System.out.println( WrapperManager.getRes().getString( "WrapperProcessStream encountered a ReadError: " ) ); ioe.printStackTrace(); } } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperProcessOutputStream.java100644 0 0 5570 12440202301 26606 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.IOException; import java.io.OutputStream; /** * The OutputStream Class of a WrapperProcess, representing all the data the * ChildProcess read from the Wrapper. * * @author Christian Mueller * @since Wrapper 3.4.0 */ public class WrapperProcessOutputStream extends OutputStream { private long m_ptr; private boolean m_closed; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * This class can only be instantiated by native code. */ private WrapperProcessOutputStream() { } /*--------------------------------------------------------------- * Native Methods *-------------------------------------------------------------*/ private native void nativeWrite( int b ); private native void nativeClose(); /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Writes a byte to the Stream. * * @param b byte to write. * * @throws IOException in case the stream has been already closed or any * other IO error. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. * */ public void write( int b ) throws IOException { synchronized( this ) { if ( ( !m_closed ) && WrapperManager.isNativeLibraryOk() ) { nativeWrite( b ); } else { throw new IOException( WrapperManager.getRes().getString( "Stream is closed." ) ); } } } /** * Closes the OutputStream. * * @throws IOException If there were any problems closing the stream. * @throws WrapperLicenseError If the function is called other than in * the Professional Edition or from a Standalone JVM. */ public void close() throws IOException { synchronized( this ) { if ( !m_closed ) { if ( WrapperManager.isNativeLibraryOk() ) { nativeClose(); } m_closed = true; } } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperProperties.java100644 0 0 6216 12440202301 24725 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.InputStream; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Properties; import java.util.Set; /** * Provides a Properties object which can be locked to prevent modification * by the user. * * @author Leif Mortenson */ class WrapperProperties extends Properties { /** * Serial Version UID. */ private static final long serialVersionUID = 1991422118345246456L; boolean m_locked = false; /** * Locks the Properties object against future modification. */ public void lock() { m_locked = true; } public void load( InputStream inStream ) throws IOException { if ( m_locked ) { throw new IllegalStateException( WrapperManager.getRes().getString( "Read Only" ) ); } super.load( inStream ); } public Object setProperty( String key, String value ) { if ( m_locked ) { throw new IllegalStateException( WrapperManager.getRes().getString( "Read Only" ) ); } return super.setProperty( key, value ); } public void clear() { if ( m_locked ) { throw new IllegalStateException( WrapperManager.getRes().getString( "Read Only" ) ); } super.clear(); } public Set entrySet() { if ( m_locked ) { return Collections.unmodifiableSet( super.entrySet() ); } else { return super.entrySet(); } } public Set keySet() { if ( m_locked ) { return Collections.unmodifiableSet( super.keySet() ); } else { return super.keySet(); } } public Object put( Object key, Object value ) { if ( m_locked ) { throw new IllegalStateException( WrapperManager.getRes().getString( "Read Only" ) ); } return super.put( key, value ); } public void putAll( Map map ) { if ( m_locked ) { throw new IllegalStateException( WrapperManager.getRes().getString( "Read Only" ) ); } super.putAll( map ); } public Object remove( Object key ) { if ( m_locked ) { throw new IllegalStateException( WrapperManager.getRes().getString( "Read Only" ) ); } return super.remove( key ); } public Collection values() { if ( m_locked ) { return Collections.unmodifiableCollection( super.values() ); } else { return super.values(); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperPropertyUtil.java100644 0 0 6667 12440202301 25265 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * A collection of utility methods which make it easy to work with Wrapper * configuration Properties without littering code with error handling. * * System Properties can be accessed with the WrapperSystemPropertyUtil * class. * * @author Leif Mortenson */ public final class WrapperPropertyUtil { /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ /** * Resolves a string property. * * @param name The name of the property to lookup. * @param defaultValue The value to return if it is not set or is invalid. * * @return The requested property value. */ public static String getStringProperty( String name, String defaultValue ) { String val = WrapperManager.getProperties().getProperty( name ); if ( val == null ) { return defaultValue; } return val; } /** * Resolves a boolean property. * * @param name The name of the property to lookup. * @param defaultValue The value to return if it is not set or is invalid. * * @return The requested property value. */ public static boolean getBooleanProperty( String name, boolean defaultValue ) { String val = getStringProperty( name, null ); if ( val == null ) { return defaultValue; } return val.equalsIgnoreCase( "TRUE" ); } /** * Resolves an integer property. * * @param name The name of the property to lookup. * @param defaultValue The value to return if it is not set or is invalid. * * @return The requested property value. */ public static int getIntProperty( String name, int defaultValue ) { String val = getStringProperty( name, null ); if ( val == null ) { return defaultValue; } try { return Integer.parseInt( val ); } catch ( NumberFormatException e ) { return defaultValue; } } /** * Resolves a long property. * * @param name The name of the property to lookup. * @param defaultValue The value to return if it is not set or is invalid. * * @return The requested property value. */ public static long getLongProperty( String name, long defaultValue ) { String val = getStringProperty( name, null ); if ( val == null ) { return defaultValue; } try { return Long.parseLong( val ); } catch ( NumberFormatException e ) { return defaultValue; } } /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Not instantiable. */ private WrapperPropertyUtil() { } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperResources.java100644 0 0 25334 12440202301 24565 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.text.MessageFormat; /** * A resource bundle which is used to help localize applications to the default * locale of the JVM. Resources are stored in MO files using the standard UNIX * gettext resources. * * For example,

* * WrapperResources res = WrapperManager.loadWrapperResources( "myapp", "../lang/" ); * * * To use the WrapperResources, make a call to any of the getString() * methods. If the resource files are not found, or the specific key is not found * then the key is returned unmodified. * * All resource keys passed to getString() will be processed using the * java.util.MessageFormat class. As such, single quotes must be escaped. * This class can optionally validate all such keys and logs warnings about * keys which fail these checks. It is possible to enable this validation with * the following property. (Defaults to FALSE) * -Dorg.tanukisoftware.wrapper.WrapperResources.validateResourceKeys=TRUE * * @author Leif Mortenson */ public final class WrapperResources { /** Error level log channel */ private static WrapperPrintStream m_outError; /** True if resource keys should be validated. */ private static boolean m_validateResourceKeys; /** Helper object to reduce number of new objects. */ private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; /** Id of the resource. Assigned within native code. */ private long m_Id; /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ static { m_outError = new WrapperPrintStream( System.out, "WrapperResources Error: " ); m_validateResourceKeys = WrapperSystemPropertyUtil.getBooleanProperty( WrapperResources.class.getName() + ".validateResourceKeys", false ); } /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * WrapperResources instances are created using the WrapperManager.loadWrapperResources method. */ protected WrapperResources() { } /*--------------------------------------------------------------- * Finalizers *-------------------------------------------------------------*/ protected void finalize() throws Throwable { try { if ( WrapperManager.isLoggingFinalizers() ) { // This can't be localized because of when it happens. System.out.println( "WrapperResources.finalize Id=" + m_Id ); } if ( m_Id != 0 ) { if ( WrapperManager.isNativeLibraryOk() ) { // clean up after the resource. nativeDestroyResource(); } } } finally { super.finalize(); } } /*--------------------------------------------------------------- * Native Methods *-------------------------------------------------------------*/ private native String nativeGetLocalizedString(String key); private native void nativeDestroyResource(); /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Checks the resource key to make sure that all of its single quotes are excaped correctly. * * @param str String which was or will be localized. * @param localized True if str is a localized string, false if it is the key. */ private void validateResourceKey( String str, boolean localized ) { int pos = 0; int len = str.length(); do { pos = str.indexOf( '\'', pos ); if ( pos < 0 ) { break; } pos++; if ( ( pos >= len ) || ( str.charAt( pos ) != '\'' ) ) { // Unescaped quote at end of string. // If one of the following keys or their localized strings have such a problem this will recurse. if ( localized ) { m_outError.println( WrapperManager.getRes().getString( "Localized resource string''s single quotes not escaped correctly: {0}", str ) ); } else { m_outError.println( WrapperManager.getRes().getString( "Resource key''s single quotes not escaped correctly: {0}", str ) ); } break; } pos++; } while ( pos < len ); } /** * Request a localized version of the specified key. * * The returned string will be the raw string which has not yet * been processed by MessageFormat. * * @param key Resource to be localized. * * @return The localized version of the key. */ private String getStringInner( String key ) { if ( m_validateResourceKeys ) { validateResourceKey( key, false ); } if ( ( m_Id != 0 ) && WrapperManager.isNativeLibraryOk() ) { String str = nativeGetLocalizedString( key ); if ( !str.equals( key ) ) { if ( m_validateResourceKeys ) { validateResourceKey( str, true ); } } return str; } else { return key; } } /** * Request a localized version of the specified key. * * @param key Resource to be localized. * * @return The localized version of the key. */ public String getString( String key ) { // Even through we are not replacing any tokens, always call the format // method so things like escaped quotes will be handled in a consistent way. return MessageFormat.format( getStringInner( key ), EMPTY_OBJECT_ARRAY ); } /** * Request a localized version of the specified key. *

* Individual tokens will be replaced with the specified parameters using the * Java MessageFormat format method. * * @param key Resource to be localized. * @param arguments An array of argumens to be replaced in the resource. * * @return The localized version of the key. * * @see java.text.MessageFormat */ public String getString( String key, Object[] arguments ) { return MessageFormat.format( getStringInner( key ), arguments ); } /** * Request a localized version of the specified key. *

* Individual tokens will be replaced with the specified parameters using the * Java MessageFormat format method. * * @param key Resource to be localized. * @param arg0 An argument to be replaced in the resource. * * @return The localized version of the key. * * @see java.text.MessageFormat */ public String getString( String key, Object arg0 ) { return MessageFormat.format( getStringInner( key ), new Object[] { arg0 } ); } /** * Request a localized version of the specified key. *

* Individual tokens will be replaced with the specified parameters using the * Java MessageFormat format method. * * @param key Resource to be localized. * @param arg0 An argument to be replaced in the resource. * @param arg1 An argument to be replaced in the resource. * * @return The localized version of the key. * * @see java.text.MessageFormat */ public String getString( String key, Object arg0, Object arg1 ) { return MessageFormat.format( getStringInner( key ), new Object[] { arg0, arg1 } ); } /** * Request a localized version of the specified key. *

* Individual tokens will be replaced with the specified parameters using the * Java MessageFormat format method. * * @param key Resource to be localized. * @param arg0 An argument to be replaced in the resource. * @param arg1 An argument to be replaced in the resource. * @param arg2 An argument to be replaced in the resource. * * @return The localized version of the key. * * @see java.text.MessageFormat */ public String getString( String key, Object arg0, Object arg1, Object arg2 ) { return MessageFormat.format( getStringInner( key ), new Object[] { arg0, arg1, arg2 } ); } /** * Request a localized version of the specified key. *

* Individual tokens will be replaced with the specified parameters using the * Java MessageFormat format method. * * @param key Resource to be localized. * @param arg0 An argument to be replaced in the resource. * @param arg1 An argument to be replaced in the resource. * @param arg2 An argument to be replaced in the resource. * @param arg3 An argument to be replaced in the resource. * * @return The localized version of the key. * * @see java.text.MessageFormat */ public String getString( String key, Object arg0, Object arg1, Object arg2, Object arg3 ) { return MessageFormat.format( getStringInner( key ), new Object[] { arg0, arg1, arg2, arg3 } ); } /** * Request a localized version of the specified key. *

* Individual tokens will be replaced with the specified parameters using the * Java MessageFormat format method. * * @param key Resource to be localized. * @param arg0 An argument to be replaced in the resource. * @param arg1 An argument to be replaced in the resource. * @param arg2 An argument to be replaced in the resource. * @param arg3 An argument to be replaced in the resource. * @param arg4 An argument to be replaced in the resource. * * @return The localized version of the key. * * @see java.text.MessageFormat */ public String getString( String key, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4 ) { return MessageFormat.format( getStringInner( key ), new Object[] { arg0, arg1, arg2, arg3, arg4 } ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperServiceException.java100644 0 0 3654 12440202301 26053 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperServiceExceptions are thrown when the Wrapper is unable to obtain * information on a requested service. * * @author Leif Mortenson */ public class WrapperServiceException extends Exception { /** * Serial Version UID. */ private static final long serialVersionUID = 5163822791166376887L; /** * The error code. */ private final int m_errorCode; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperServiceException. * * @param errorCode ErrorCode which was encountered. * @param message Message describing the exception. */ WrapperServiceException( int errorCode, byte[] message ) { super( new String( message ) ); m_errorCode = errorCode; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the error code. * * @return The error code. */ public int getErrorCode() { return m_errorCode; } /** * Return string representation of the Exception. * * @return String representation of the Exception. */ public String toString() { return this.getClass().getName() + " " + getMessage() + WrapperManager.getRes().getString( " Error Code: " ) + getErrorCode(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperShuttingDownException.java100644 0 0 1716 12440202301 27105 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperShuttingDownExceptions are thrown when certain Wrapper functions * are accessed after the Wrapper has started shutting down. * * @author Leif Mortenson */ public class WrapperShuttingDownException extends Exception { /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperShuttingDownException. */ WrapperShuttingDownException() { super(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperSimpleApp.java100644 0 0 57470 12440202301 24513 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; /** * By default the WrapperSimpleApp will only wait for 2 seconds for the main * method of the start class to complete. This was done because the main * methods of many applications never return. It is possible to force the * class to wait for the startup main method to complete by defining the * following system property when launching the JVM (defaults to FALSE): * -Dorg.tanukisoftware.wrapper.WrapperSimpleApp.waitForStartMain=TRUE *

* Using the waitForStartMain property will cause the startup to wait * indefinitely. This is fine if the main method will always return * within a predefined period of time. But if there is any chance that * it could hang, then the maxStartMainWait property may be a better * option. It allows the 2 second wait time to be overridden. To wait * for up to 5 minutes for the startup main method to complete, set * the property to 300 as follows (defaults to 2 seconds): * -Dorg.tanukisoftware.wrapper.WrapperSimpleApp.maxStartMainWait=300 *

* By default, the WrapperSimpleApp will tell the Wrapper to exit with an * exit code of 1 if any uncaught exceptions are thrown in the configured * main method. This is good in most cases, but is a little different than * the way Java works on its own. Java will stay up and running if it has * launched any other non-daemon threads even if the main method ends because * of an uncaught exception. To get this same behavior, it is possible to * specify the following system property when launching the JVM (defaults to * FALSE): * -Dorg.tanukisoftware.wrapper.WrapperSimpleApp.ignoreMainExceptions=TRUE *

* It is possible to extend this class but make absolutely sure that any * overridden methods call their super method or the class will fail to * function correctly. Most users will have no need to override this * class. Remember that if overridden, the main method will also need to * be recreated in the child class to make sure that the correct instance * is created. *

* NOTE - The main methods of many applications are designed not to * return. In these cases, you must either stick with the default 2 second * startup timeout or specify a slightly longer timeout, using the * maxStartMainWait property, to simulate the amount of time your application * takes to start up. *

* WARNING - If the waitForStartMain is specified for an application * whose start method never returns, the Wrapper will appear at first to be * functioning correctly. However the Wrapper will never enter a running * state, this means that the Windows Service Manager and several of the * Wrapper's error recovery mechanisms will not function correctly. * * @author Leif Mortenson */ public class WrapperSimpleApp implements WrapperListener, Runnable { /** Info level log channel */ private static WrapperPrintStream m_outInfo; /** Error level log channel */ private static WrapperPrintStream m_outError; /** Debug level log channel */ private static WrapperPrintStream m_outDebug; /** * Application's main method */ private Method m_mainMethod; /** * Command line arguments to be passed on to the application */ private String[] m_appArgs; /** * Gets set to true when the thread used to launch the application * actuially starts. */ private boolean m_mainStarted; /** * Gets set to true when the thread used to launch the application * completes. */ private boolean m_mainComplete; /** * Exit code to be returned if the application fails to start. */ private Integer m_mainExitCode; /** * True if uncaught exceptions in the user app's main method should be ignored. */ private boolean m_ignoreMainExceptions; /** * Flag used to signify that the start method has completed. */ private boolean m_startComplete; /** * Flag that is set if there were any initialization problems. */ private boolean m_initFailed; /** * Error message which should be shown if initialization Failed. */ private String m_initError; /** * True if usage should be shown as part of an initialization error. */ private boolean m_initShowUsage; /** * The exception which caused the error. Only needs to be set if the stacktrace is required. */ private Throwable m_initException; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates an instance of a WrapperSimpleApp. * * @param args The full list of arguments passed to the JVM. */ protected WrapperSimpleApp( String args[] ) { // Initialize the WrapperManager class on startup by referencing it. Class wmClass = WrapperManager.class; m_mainMethod = null; // Set up some log channels m_outInfo = new WrapperPrintStream( System.out, "WrapperSimpleApp: " ); m_outError = new WrapperPrintStream( System.out, "WrapperSimpleApp Error: " ); m_outDebug = new WrapperPrintStream( System.out, "WrapperSimpleApp Debug: " ); // Do all of our initialization here so the modified array list which is passed // to the WrapperListener.start method can remain unchanged. Ideally we would // want to handle this within the start method, but that would be an API change // that could effect users. // appArgs will be an args array with the main class name stripped off. String[] appArgs; // Get the class name of the application if ( args.length < 1 ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Not enough argments. Minimum {0} required.", "1" ); m_initShowUsage = true; // No main class, do the best we can for now. appArgs = new String[0]; } else { // Look for the specified class by name String ar[] = args[0].split( "/" ); String mainClassString; String mainMethodString; if ( ar.length > 1 ) { mainClassString = ar[0]; mainMethodString = ar[1]; } else { mainClassString = args[0]; mainMethodString = "main"; } Class mainClass; try { mainClass = Class.forName( mainClassString ); } catch ( ClassNotFoundException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate the class {0} : {1}", mainClassString, e ); m_initShowUsage = true; mainClass = null; } catch ( ExceptionInInitializerError e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Class {0} found but could not be initialized due to:", mainClassString ); m_initException = e; mainClass = null; } catch ( LinkageError e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Class {0} found but could not be initialized: {1}", mainClassString, e ); mainClass = null; } if ( !m_initFailed ) { // Look for the main method try { // getDeclaredMethod will return any method named main in the specified class, // while getMethod will only return public methods, but it will search up the // inheritance path. m_mainMethod = mainClass.getMethod( mainMethodString, new Class[] { String[].class } ); } catch ( NoSuchMethodException e ) { try { // getDeclaredMethod will return any method named in the specified class, // while getMethod will only return public methods, but it will search up the // inheritance path. // try without parameters m_mainMethod = mainClass.getMethod( mainMethodString, new Class[] { } ); } catch ( NoSuchMethodException e2 ) { // Handle with first exception. } if ( m_mainMethod == null ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate a public static {2} method in class {0} : {1}", mainClassString, e, mainMethodString ); } } catch ( SecurityException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate a public static {2} method in class {0} : {1}", mainClassString, e, mainMethodString ); } if ( !m_initFailed ) { // Make sure that the method is public and static int modifiers = m_mainMethod.getModifiers(); if ( !( Modifier.isPublic( modifiers ) && Modifier.isStatic( modifiers ) ) ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "The {1} method in class {0} must be declared public and static.", mainClassString, mainMethodString ); } } } // Strip the main class off of the args list. // This is assuming the main class was valid for now. appArgs = new String[args.length - 1]; System.arraycopy( args, 1, appArgs, 0, appArgs.length ); } // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start( this, appArgs ); // This thread ends, the WrapperManager will start the application after the Wrapper has // been properly initialized by calling the start method above. } /*--------------------------------------------------------------- * Runnable Methods *-------------------------------------------------------------*/ /** * Used to launch the application in a separate thread. */ public void run() { // Notify the start method that the thread has been started by the JVM. synchronized( this ) { m_mainStarted = true; notifyAll(); } Throwable t = null; try { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "invoking main method" ) ); } try { try { m_mainMethod.invoke( null, new Object[] { m_appArgs } ); } catch ( IllegalArgumentException iae ) { m_mainMethod.invoke( null, new Object[] { } ); } } finally { // Make sure the rest of this thread does not fall behind the application. Thread.currentThread().setPriority( Thread.MAX_PRIORITY ); } if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "main method completed" ) ); } synchronized(this) { // Let the start() method know that the main method returned, in case it is // still waiting. m_mainComplete = true; this.notifyAll(); } return; } catch ( IllegalAccessException e ) { t = e; } catch ( IllegalArgumentException e ) { t = e; } catch ( InvocationTargetException e ) { t = e.getTargetException(); if ( t == null ) { t = e; } } // If we get here, then an error was thrown. If this happened quickly // enough, the start method should be allowed to shut things down. m_outInfo.println(); m_outError.println( WrapperManager.getRes().getString( "Encountered an error running main:" ) ); // We should print a stack trace here, because in the case of an // InvocationTargetException, the user needs to know what exception // their app threw. t.printStackTrace( m_outError ); synchronized( this ) { if ( m_ignoreMainExceptions ) { if ( !m_startComplete ) { // An exception was thrown, but we want to let the application continue. m_mainComplete = true; this.notifyAll(); } return; } else { if ( m_startComplete ) { // Shut down here. WrapperManager.stop( 1 ); return; // Will not get here. } else { // Let start method handle shutdown. m_mainComplete = true; m_mainExitCode = new Integer( 1 ); this.notifyAll(); return; } } } } /*--------------------------------------------------------------- * WrapperListener Methods *-------------------------------------------------------------*/ /** * The start method is called when the WrapperManager is signalled by the * native wrapper code that it can start its application. This * method call is expected to return, so a new thread should be launched * if necessary. * If there are any problems, then an Integer should be returned, set to * the desired exit code. If the application should continue, * return null. * * @param args Arguments passed to the application. */ public Integer start( String[] args ) { // See if there were any startup problems. if ( m_initFailed ) { if ( m_initError != null ) { m_outError.println( m_initError ); } if ( m_initException != null ) { m_initException.printStackTrace( m_outError ); } if ( m_initShowUsage ) { showUsage(); } return new Integer( 1 ); } // Decide whether or not to wait for the start main method to complete before returning. boolean waitForStartMain = WrapperSystemPropertyUtil.getBooleanProperty( WrapperSimpleApp.class.getName() + ".waitForStartMain", false ); m_ignoreMainExceptions = WrapperSystemPropertyUtil.getBooleanProperty( WrapperSimpleApp.class.getName() + ".ignoreMainExceptions", false ); int maxStartMainWait = WrapperSystemPropertyUtil.getIntProperty( WrapperSimpleApp.class.getName() + ".maxStartMainWait", 2 ); maxStartMainWait = Math.max( 1, maxStartMainWait ); // Decide the maximum number of times to loop waiting for the main start method. int maxLoops; if ( waitForStartMain ) { maxLoops = Integer.MAX_VALUE; if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) Will wait indefinitely for the main method to complete." ) ); } } else { maxLoops = maxStartMainWait; // 1s loops. if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) Will wait up to {0} seconds for the main method to complete.", new Integer(maxLoops) ) ); } } Thread mainThread = new Thread( this, "WrapperSimpleAppMain" ); synchronized(this) { m_appArgs = args; mainThread.start(); // Make sure the rest of this thread does not fall behind the application. Thread.currentThread().setPriority( Thread.MAX_PRIORITY ); // To avoid problems with the main thread starting slowly on heavily loaded systems, // do not continue until the thread has actually started. while ( !m_mainStarted ) { try { this.wait( 1000 ); } catch ( InterruptedException e ) { // Continue. } } // Wait for startup main method to complete. int loops = 0; while ( ( loops < maxLoops ) && ( !m_mainComplete ) ) { try { this.wait( 1000 ); } catch ( InterruptedException e ) { // Continue. } if ( !m_mainComplete ) { // If maxLoops is large then this could take a while. Notify the // WrapperManager that we are still starting so it doesn't give up. WrapperManager.signalStarting( 5000 ); } loops++; } // Always set the flag stating that the start method completed. This is needed // so the run method can decide whether or not it needs to be responsible for // shutting down the JVM in the event of an exception thrown by the start main // method. m_startComplete = true; // The main exit code will be null unless an error was thrown by the start // main method. if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) end. Main Completed={0}, exitCode={1}", new Boolean( m_mainComplete ), m_mainExitCode ) ); } return m_mainExitCode; } } /** * Called when the application is shutting down. */ public int stop( int exitCode ) { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "stop({0})", new Integer ( exitCode ) ) ); } // Normally an application will be asked to shutdown here. Standard Java applications do // not have shutdown hooks, so do nothing here. It will be as if the user hit CTRL-C to // kill the application. return exitCode; } /** * Called whenever the native wrapper code traps a system control signal * against the Java process. It is up to the callback to take any actions * necessary. Possible values are: WrapperManager.WRAPPER_CTRL_C_EVENT, * WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, or * WRAPPER_CTRL_SHUTDOWN_EVENT */ public void controlEvent( int event ) { if ( ( event == WrapperManager.WRAPPER_CTRL_LOGOFF_EVENT ) && ( WrapperManager.isLaunchedAsService() || WrapperManager.isIgnoreUserLogoffs() ) ) { // Ignore m_outInfo.println( WrapperManager.getRes().getString( "User logged out. Ignored." ) ); } else { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "controlEvent({0}) Stopping", new Integer( event ) ) ); } WrapperManager.stop( 0 ); // Will not get here. } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Displays application usage */ protected void showUsage() { // Show this output without headers. System.out.println(); System.out.println( WrapperManager.getRes().getString( "WrapperSimpleApp Usage:" ) ); System.out.println( WrapperManager.getRes().getString( " java org.tanukisoftware.wrapper.WrapperSimpleApp {app_class{/app_method}} [app_arguments]" ) ); System.out.println(); System.out.println( WrapperManager.getRes().getString( "Where:" ) ); System.out.println( WrapperManager.getRes().getString( " app_class: The fully qualified class name of the application to run." ) ); System.out.println( WrapperManager.getRes().getString( " app_arguments: The arguments that would normally be passed to the" ) ); System.out.println( WrapperManager.getRes().getString( " application." ) ); } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ /** * Used to Wrapper enable a standard Java application. This main * expects the first argument to be the class name of the application * to launch. All remaining arguments will be wrapped into a new * argument list and passed to the main method of the specified * application. * * @param args Arguments passed to the application. */ public static void main( String args[] ) { new WrapperSimpleApp( args ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperStartStopApp.java100644 0 0 103512 12440202301 25232 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; /** * By default the WrapperStartStopApp will only wait for 2 seconds for the main * method of the start class to complete. This was done because the main * methods of many applications never return. It is possible to force the * class to wait for the startup main method to complete by defining the * following system property when launching the JVM (defaults to FALSE): * -Dorg.tanukisoftware.wrapper.WrapperStartStopApp.waitForStartMain=TRUE *

* Using the waitForStartMain property will cause the startup to wait * indefinitely. This is fine if the main method will always return * within a predefined period of time. But if there is any chance that * it could hang, then the maxStartMainWait property may be a better * option. It allows the 2 second wait time to be overridden. To wait * for up to 5 minutes for the startup main method to complete, set * the property to 300 as follows (defaults to 2 seconds): * -Dorg.tanukisoftware.wrapper.WrapperStartStopApp.maxStartMainWait=300 *

* By default, the WrapperStartStopApp will tell the Wrapper to exit with an * exit code of 1 if any uncaught exceptions are thrown in the configured * main method. This is good in most cases, but is a little different than * the way Java works on its own. Java will stay up and running if it has * launched any other non-daemon threads even if the main method ends because * of an uncaught exception. To get this same behavior, it is possible to * specify the following system property when launching the JVM (defaults to * FALSE): * -Dorg.tanukisoftware.wrapper.WrapperStartStopApp.ignoreMainExceptions=TRUE *

* It is possible to extend this class but make absolutely sure that any * overridden methods call their super method or the class will fail to * function correctly. Most users will have no need to override this * class. Remember that if overridden, the main method will also need to * be recreated in the child class to make sure that the correct instance * is created. *

* NOTE - The main methods of many applications are designed not to * return. In these cases, you must either stick with the default 2 second * startup timeout or specify a slightly longer timeout, using the * maxStartMainWait property, to simulate the amount of time your application * takes to start up. *

* WARNING - If the waitForStartMain is specified for an application * whose start method never returns, the Wrapper will appear at first to be * functioning correctly. However the Wrapper will never enter a running * state, this means that the Windows Service Manager and several of the * Wrapper's error recovery mechanisms will not function correctly. * * @author Leif Mortenson */ public class WrapperStartStopApp implements WrapperListener, Runnable { /** Info level log channel */ private static WrapperPrintStream m_outInfo; /** Error level log channel */ private static WrapperPrintStream m_outError; /** Debug level log channel */ private static WrapperPrintStream m_outDebug; /** * Application's start main method */ private Method m_startMainMethod; /** * Command line arguments to be passed on to the start main method */ private String[] m_startMainArgs; /** * Application's stop main method */ private Method m_stopMainMethod; /** * Should the stop process force the JVM to exit, or wait for all threads * to die on their own. */ private boolean m_stopWait; /** * Command line arguments to be passed on to the stop main method */ private String[] m_stopMainArgs; /** * Gets set to true when the thread used to launch the application * actuially starts. */ private boolean m_mainStarted; /** * Gets set to true when the thread used to launch the application * completes. */ private boolean m_mainComplete; /** * Exit code to be returned if the application fails to start. */ private Integer m_mainExitCode; /** * True if uncaught exceptions in the user app's main method should be ignored. */ private boolean m_ignoreMainExceptions; /** * Flag used to signify that the start method has completed. */ private boolean m_startComplete; /** * Flag that is set if there were any initialization problems. */ private boolean m_initFailed; /** * Error message which should be shown if initialization Failed. */ private String m_initError; /** * True if usage should be shown as part of an initialization error. */ private boolean m_initShowUsage; /** * The exception which caused the error. Only needs to be set if the stacktrace is required. */ private Throwable m_initException; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates an instance of a WrapperStartStopApp. * * @param args The full list of arguments passed to the JVM. */ protected WrapperStartStopApp( String args[] ) { // Initialize the WrapperManager class on startup by referencing it. Class wmClass = WrapperManager.class; // Set up some log channels m_outInfo = new WrapperPrintStream( System.out, "WrapperStartStopApp: " ); m_outError = new WrapperPrintStream( System.out, "WrapperStartStopApp Error: " ); m_outDebug = new WrapperPrintStream( System.out, "WrapperStartStopApp Debug: " ); // Do all of our initialization here so the modified array lists which are passed // to the WrapperListener.start method can remain unchanged. Ideally we would // want to handle this within the start method, but that would be an API change // that could effect users. // startArgs will be an args array with the main class name and stop args stripped off. String[] startArgs; // Get the class name of the application if ( args.length < 5 ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Not enough argments. Minimum {0} required.", "5" ); m_initShowUsage = true; // No main class, do the best we can for now. startArgs = new String[0]; } else { // Look for the start main method. m_startMainMethod = getMainMethod( args[0] ); // Get the start arguments startArgs = getArgs( args, 1 ); if ( startArgs == null ) { // Failed, but we need an empty array for the start method below. startArgs = new String[0]; // m_initFailed and m_initError already set. } else { // Where do the stop arguments start int stopArgBase = 2 + startArgs.length; if ( args.length < stopArgBase + 3 ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Not enough argments. Minimum 3 after start arguments." ); m_initShowUsage = true; } else { // Look for the stop main method. m_stopMainMethod = getMainMethod( args[stopArgBase] ); // Get the stopWait flag if ( args[stopArgBase + 1].equalsIgnoreCase( "true" ) ) { m_stopWait = true; } else if ( args[stopArgBase + 1].equalsIgnoreCase( "false" ) ) { m_stopWait = false; } else { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "The stop_wait argument must be either true or false." ); m_initShowUsage = true; } if ( !m_initFailed ) { // Get the start arguments m_stopMainArgs = getArgs( args, stopArgBase + 2 ); if ( m_stopMainArgs == null ) { // m_initFailed and m_initError already set. } } } } } // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start( this, startArgs ); // This thread ends, the WrapperManager will start the application after the Wrapper has // been propperly initialized by calling the start method above. } /** * Helper method to make it easier for user classes extending this class to have their * own methods of parsing the command line. */ protected WrapperStartStopApp( Method startMainMethod, Method stopMainMethod, boolean stopWait, String[] stopMainArgs ) { m_startMainMethod = startMainMethod; m_stopMainMethod = stopMainMethod; m_stopWait = stopWait; m_stopMainArgs = stopMainArgs; // NOTE - The call to WrapperManager.start() appears to be missing here, but it can't be added // as doing so would break how existing users are making use of this constructor. } /*--------------------------------------------------------------- * Runnable Methods *-------------------------------------------------------------*/ /** * Used to launch the application in a separate thread. */ public void run() { // Notify the start method that the thread has been started by the JVM. synchronized( this ) { m_mainStarted = true; notifyAll(); } Throwable t = null; try { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "invoking start main method" ) ); } try { try { m_startMainMethod.invoke( null, new Object[] { m_startMainArgs } ); } catch ( IllegalArgumentException iae ) { m_startMainMethod.invoke( null, new Object[] { } ); } } finally { // Make sure the rest of this thread does not fall behind the application. Thread.currentThread().setPriority( Thread.MAX_PRIORITY ); } if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start main method completed" ) ); } synchronized(this) { // Let the start() method know that the main method returned, in case it is // still waiting. m_mainComplete = true; this.notifyAll(); } return; } catch ( IllegalAccessException e ) { t = e; } catch ( IllegalArgumentException e ) { t = e; } catch ( InvocationTargetException e ) { t = e.getTargetException(); if ( t == null ) { t = e; } } // If we get here, then an error was thrown. If this happened quickly // enough, the start method should be allowed to shut things down. m_outInfo.println(); m_outError.println( WrapperManager.getRes().getString( "Encountered an error running start main: {0}", t ) ); // We should print a stack trace here, because in the case of an // InvocationTargetException, the user needs to know what exception // their app threw. t.printStackTrace( m_outError ); synchronized( this ) { if ( m_ignoreMainExceptions ) { if ( !m_startComplete ) { // An exception was thrown, but we want to let the application continue. m_mainComplete = true; this.notifyAll(); } return; } else { if ( m_startComplete ) { // Shut down here. WrapperManager.stop( 1 ); return; // Will not get here. } else { // Let start method handle shutdown. m_mainComplete = true; m_mainExitCode = new Integer( 1 ); this.notifyAll(); return; } } } } /*--------------------------------------------------------------- * WrapperListener Methods *-------------------------------------------------------------*/ /** * The start method is called when the WrapperManager is signalled by the * native wrapper code that it can start its application. This * method call is expected to return, so a new thread should be launched * if necessary. * If there are any problems, then an Integer should be returned, set to * the desired exit code. If the application should continue, * return null. */ public Integer start( String[] args ) { // See if there were any startup problems. if ( m_initFailed ) { if ( m_initError != null ) { m_outError.println( m_initError ); } if ( m_initException != null ) { m_initException.printStackTrace( m_outError ); } if ( m_initShowUsage ) { showUsage(); } return new Integer( 1 ); } // Decide whether or not to wait for the start main method to complete before returning. boolean waitForStartMain = WrapperSystemPropertyUtil.getBooleanProperty( WrapperStartStopApp.class.getName() + ".waitForStartMain", false ); m_ignoreMainExceptions = WrapperSystemPropertyUtil.getBooleanProperty( WrapperStartStopApp.class.getName() + ".ignoreMainExceptions", false ); int maxStartMainWait = WrapperSystemPropertyUtil.getIntProperty( WrapperStartStopApp.class.getName() + ".maxStartMainWait", 2 ); maxStartMainWait = Math.max( 1, maxStartMainWait ); // Decide the maximum number of times to loop waiting for the main start method. int maxLoops; if ( waitForStartMain ) { maxLoops = Integer.MAX_VALUE; if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) Will wait indefinitely for the main method to complete." ) ); } } else { maxLoops = maxStartMainWait; // 1s loops. if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) Will wait up to {0} seconds for the main method to complete.", new Integer(maxLoops) ) ); } } Thread mainThread = new Thread( this, "WrapperStartStopAppMain" ); synchronized(this) { m_startMainArgs = args; mainThread.start(); // Make sure the rest of this thread does not fall behind the application. Thread.currentThread().setPriority( Thread.MAX_PRIORITY ); // To avoid problems with the main thread starting slowly on heavily loaded systems, // do not continue until the thread has actually started. while ( !m_mainStarted ) { try { this.wait( 1000 ); } catch ( InterruptedException e ) { // Continue. } } // Wait for startup main method to complete. int loops = 0; while ( ( loops < maxLoops ) && ( !m_mainComplete ) ) { try { this.wait( 1000 ); } catch ( InterruptedException e ) { // Continue. } if ( !m_mainComplete ) { // If maxLoops is large then this could take a while. Notify the // WrapperManager that we are still starting so it doesn't give up. WrapperManager.signalStarting( 5000 ); } loops++; } // Always set the flag stating that the start method completed. This is needed // so the run method can decide whether or not it needs to be responsible for // shutting down the JVM in the event of an exception thrown by the start main // method. m_startComplete = true; // The main exit code will be null unless an error was thrown by the start // main method. if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "start(args) end. Main Completed={0}, exitCode={1}", new Boolean( m_mainComplete ), m_mainExitCode ) ); } return m_mainExitCode; } } /** * Called when the application is shutting down. */ public int stop( int exitCode ) { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println(WrapperManager.getRes().getString( "stop({0})", new Integer( exitCode ) ) ); } // Execute the main method in the stop class Throwable t = null; try { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "invoking stop main method" ) ); } try { m_stopMainMethod.invoke( null, new Object[] { m_stopMainArgs } ); } catch ( IllegalArgumentException iae ) { m_stopMainMethod.invoke( null, new Object[] { } ); } if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "stop main method completed" ) ); } if ( m_stopWait ) { // This feature exists to make sure the stop process waits for the main // application to fully shutdown. This can only be done by looking for // and counting the number of non-daemon threads still running in the // system. int systemThreadCount = WrapperSystemPropertyUtil.getIntProperty( WrapperStartStopApp.class.getName() + ".systemThreadCount", 1 ); systemThreadCount = Math.max( 0, systemThreadCount ); int threadCnt; while( ( threadCnt = getNonDaemonThreadCount() ) > systemThreadCount ) { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "stopping. Waiting for {0} threads to complete.", new Integer( threadCnt - systemThreadCount ) ) ); } try { Thread.sleep( 1000 ); } catch ( InterruptedException e ) { } } } // Success return exitCode; } catch ( IllegalAccessException e ) { t = e; } catch ( IllegalArgumentException e ) { t = e; } catch ( InvocationTargetException e ) { t = e; } // If we get here, then an error was thrown. m_outError.println( WrapperManager.getRes().getString( "Encountered an error running stop main: {0}", t ) ); // We should print a stack trace here, because in the case of an // InvocationTargetException, the user needs to know what exception // their app threw. t.printStackTrace( m_outError ); // Return a failure exit code return 1; } /** * Called whenever the native wrapper code traps a system control signal * against the Java process. It is up to the callback to take any actions * necessary. Possible values are: WrapperManager.WRAPPER_CTRL_C_EVENT, * WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, or * WRAPPER_CTRL_SHUTDOWN_EVENT */ public void controlEvent( int event ) { if ( ( event == WrapperManager.WRAPPER_CTRL_LOGOFF_EVENT ) && ( WrapperManager.isLaunchedAsService() || WrapperManager.isIgnoreUserLogoffs() ) ) { // Ignore m_outInfo.println( WrapperManager.getRes().getString( "User logged out. Ignored." ) ); } else { if ( WrapperManager.isDebugEnabled() ) { m_outDebug.println( WrapperManager.getRes().getString( "controlEvent({0}) Stopping", new Integer( event ) ) ); } WrapperManager.stop( 0 ); // Will not get here. } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns a count of all non-daemon threads in the JVM, starting with the top * thread group. * * @return Number of non-daemon threads. */ private int getNonDaemonThreadCount() { // Locate the top thread group. ThreadGroup topGroup = Thread.currentThread().getThreadGroup(); while ( topGroup.getParent() != null ) { topGroup = topGroup.getParent(); } // Get a list of all threads. Use an array that is twice the total number of // threads as the number of running threads may be increasing as this runs. Thread[] threads = new Thread[topGroup.activeCount() * 2]; topGroup.enumerate( threads, true ); // Only count any non daemon threads which are // still alive other than this thread. int liveCount = 0; for ( int i = 0; i < threads.length; i++ ) { /* if ( threads[i] != null ) { m_outDebug.println( "Check " + threads[i].getName() + " daemon=" + threads[i].isDaemon() + " alive=" + threads[i].isAlive() ); } */ if ( ( threads[i] != null ) && threads[i].isAlive() ) { // Do not count this thread. if ( ( Thread.currentThread() != threads[i] ) && ( !threads[i].isDaemon() ) ) { // Non-Daemon living thread liveCount++; //m_outDebug.println( " -> Non-Daemon" ); } } } //m_outDebug.println( " => liveCount = " + liveCount ); return liveCount; } /** * Returns the main method of the specified class. If there are any problems, * an error message will be displayed and the Wrapper will be stopped. This * method will only return if it has a valid method. */ private Method getMainMethod( String className ) { // Look for the start class by name Class mainClass; String methodName = "main"; String [] arr = className.split("/"); if ( arr.length > 1 ) { className = arr[0]; methodName = arr[1]; } try { mainClass = Class.forName( className ); } catch ( ClassNotFoundException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate the class {0}: {1}", className, e ); m_initShowUsage = true; return null; // Will not get here } catch ( ExceptionInInitializerError e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Class {0} found but could not be initialized due to:", className ); m_initException = e; return null; // Will not get here } catch ( LinkageError e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Class {0} found but could not be initialized: {1}", className , e ); return null; // Will not get here } // Look for the start method Method mainMethod = null; try { // getDeclaredMethod will return any method named main in the specified class, // while getMethod will only return public methods, but it will search up the // inheritance path. mainMethod = mainClass.getMethod( methodName, new Class[] { String[].class } ); } catch ( NoSuchMethodException e ) { try { // getDeclaredMethod will return any method named in the specified class, // while getMethod will only return public methods, but it will search up the // inheritance path. // try without parameters mainMethod = mainClass.getMethod( methodName, new Class[] { } ); } catch ( NoSuchMethodException e2 ) { } if ( mainMethod == null ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate a public static {2} method in class {0}: {1}", className, e, methodName ); return null; // Will not get here } } catch ( SecurityException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Unable to locate a public static {2} method in class {0}: {1}", className, e, methodName ); return null; // Will not get here } // Make sure that the method is public and static int modifiers = mainMethod.getModifiers(); if ( !( Modifier.isPublic( modifiers ) && Modifier.isStatic( modifiers ) ) ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "The {1} method in class {0} must be declared public and static.", className, methodName ); return null; // Will not get here } return mainMethod; } /** * Parses a set of arguments starting with a count. * * @return the Argument list, or null if there was a problem. */ private String[] getArgs( String[] args, int argBase ) { // The arg at the arg base should be a count of the number of available arguments. int argCount; try { argCount = Integer.parseInt( args[argBase] ); } catch ( NumberFormatException e ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Illegal argument count: {0}", args[argBase] ); m_initShowUsage = true; return null; } if ( argCount < 0 ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Illegal argument count: {0}", args[argBase] ); m_initShowUsage = true; return null; } // Make sure that there are enough arguments in the array. if ( args.length < argBase + 1 + argCount ) { m_initFailed = true; m_initError = WrapperManager.getRes().getString( "Not enough argments. Argument count of {0} was specified.", new Integer( argCount) ); m_initShowUsage = true; return null; } // Create the argument array String[] mainArgs = new String[argCount]; System.arraycopy( args, argBase + 1, mainArgs, 0, argCount ); return mainArgs; } /** * Displays application usage */ protected void showUsage() { // Show this output without headers. System.out.println(); System.out.println( WrapperManager.getRes().getString( "WrapperStartStopApp Usage:" ) ); System.out.println( WrapperManager.getRes().getString( " java org.tanukisoftware.wrapper.WrapperStartStopApp {start_class{/start_method}} {start_arg_count} [start_arguments] {stop_class{/stop_method}} {stop_wait} {stop_arg_count} [stop_arguments]" ) ); System.out.println(); System.out.println( WrapperManager.getRes().getString( "Where:" ) ); System.out.println( WrapperManager.getRes().getString( " start_class: The fully qualified class name to run to start the " ) ); System.out.println( WrapperManager.getRes().getString( " application." ) ); System.out.println( WrapperManager.getRes().getString( " start_arg_count: The number of arguments to be passed to the start class''s " ) ); System.out.println( WrapperManager.getRes().getString( " main method." ) ); System.out.println( WrapperManager.getRes().getString( " start_arguments: The arguments that would normally be passed to the start " ) ); System.out.println( WrapperManager.getRes().getString( " class application." ) ); System.out.println( WrapperManager.getRes().getString( " stop_class: The fully qualified class name to run to stop the " ) ); System.out.println( WrapperManager.getRes().getString( " application." ) ); System.out.println( WrapperManager.getRes().getString( " stop_wait: When stopping, should the Wrapper wait for all threads to " ) ); System.out.println( WrapperManager.getRes().getString( " complete before exiting (true/false)." ) ); System.out.println( WrapperManager.getRes().getString( " stop_arg_count: The number of arguments to be passed to the stop class''s " ) ); System.out.println( WrapperManager.getRes().getString( " main method." ) ); System.out.println( WrapperManager.getRes().getString( " stop_arguments: The arguments that would normally be passed to the stop " ) ); System.out.println( WrapperManager.getRes().getString( " class application." ) ); } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ /** * Used to Wrapper enable a standard Java application. This main * expects the first argument to be the class name of the application * to launch. All remaining arguments will be wrapped into a new * argument list and passed to the main method of the specified * application. * * @param args Arguments passed to the application. */ public static void main( String args[] ) { new WrapperStartStopApp( args ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperSystemPropertyUtil.java100644 0 0 6506 12440202301 26462 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * A collection of utility methods which make it easy to work with System * Properties without littering code with error handling. * * @author Leif Mortenson */ public final class WrapperSystemPropertyUtil { /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ /** * Resolves a string property. * * @param name The name of the property to lookup. * @param defaultValue The value to return if it is not set or is invalid. * * @return The requested property value. */ public static String getStringProperty( String name, String defaultValue ) { String val = System.getProperty( name ); if ( val == null ) { return defaultValue; } return val; } /** * Resolves a boolean property. * * @param name The name of the property to lookup. * @param defaultValue The value to return if it is not set or is invalid. * * @return The requested property value. */ public static boolean getBooleanProperty( String name, boolean defaultValue ) { String val = getStringProperty( name, null ); if ( val == null ) { return defaultValue; } return val.equalsIgnoreCase( "TRUE" ); } /** * Resolves an integer property. * * @param name The name of the property to lookup. * @param defaultValue The value to return if it is not set or is invalid. * * @return The requested property value. */ public static int getIntProperty( String name, int defaultValue ) { String val = getStringProperty( name, null ); if ( val == null ) { return defaultValue; } try { return Integer.parseInt( val ); } catch ( NumberFormatException e ) { return defaultValue; } } /** * Resolves a long property. * * @param name The name of the property to lookup. * @param defaultValue The value to return if it is not set or is invalid. * * @return The requested property value. */ public static long getLongProperty( String name, long defaultValue ) { String val = getStringProperty( name, null ); if ( val == null ) { return defaultValue; } try { return Long.parseLong( val ); } catch ( NumberFormatException e ) { return defaultValue; } } /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Not instantiable. */ private WrapperSystemPropertyUtil() { } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperUNIXGroup.java100644 0 0 3026 12440202301 24365 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * A WrapperGroup contains information about a group which a user * belongs to. A WrapperGroup is obtained via a WrapperUser. * * @author Leif Mortenson */ public class WrapperUNIXGroup extends WrapperGroup { /** The GID of the Group. */ private int m_gid; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ WrapperUNIXGroup( int gid, String name ) { super( name ); m_gid = gid; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the GID of the group. * * @return The GID of the group. */ public int getGID() { return m_gid; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append( "WrapperUNIXGroup[" ); sb.append( getGID() ); sb.append( getGroup() ); sb.append( "]" ); return sb.toString(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperUNIXUser.java100644 0 0 11002 12440202301 24220 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * A WrapperUser contains information about a user account on the platform * running the Wrapper. A WrapperUser is obtained by calling * WrapperManager.getUser() or WrapperManager.getInteractiveUser(). * * @author Leif Mortenson */ public class WrapperUNIXUser extends WrapperUser { /** The UID of the user. */ private int m_uid; /** The GID of the user. */ private int m_gid; /** The Group of the user. */ private WrapperUNIXGroup m_group; /** The real name of the user. */ private String m_realName; /** The home directory of the user. */ private String m_home; /** The shell of the user. */ private String m_shell; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ WrapperUNIXUser( int uid, int gid, String user, String realName, String home, String shell ) { super( user ); m_uid = uid; m_gid = gid; m_realName = realName; m_home = home; m_shell = shell; // The real name field appears to contain several fields, we only want the first. int pos = m_realName.indexOf( ',' ); if ( pos == 1000 ) { m_realName = ""; } else if ( pos >= 0 ) { m_realName = m_realName.substring( 0, pos ); } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the UID of the user account. * * @return The UID of the user account. */ public int getUID() { return m_uid; } /** * Returns the GID of the user account. * * @return The GID of the user account. */ public int getGID() { return m_gid; } /** * Returns the WrapperUNIXGroup which corresponds to the GID. * Null will be returned if groups were not requested with the * user. * * @return The WrapperUNIXGroup which corresponds to the GID. */ public WrapperUNIXGroup getGroup() { return m_group; } /** * Returns the real name of the user. * * @return The real name of the user. */ public String getRealName() { return m_realName; } /** * Returns the home of the user. * * @return The home of the user. */ public String getHome() { return m_home; } /** * Returns the shell of the user. * * @return The shell of the user. */ public String getShell() { return m_shell; } /** * Called by native code to set the primary Group of the User. */ private void setGroup( int gid, String name ) { m_group = new WrapperUNIXGroup( gid, name ); addGroup( m_group ); } /** * Called by native code to add a Group to the User. */ private void addGroup( int gid, String name ) { addGroup( new WrapperUNIXGroup( gid, name ) ); } /** * Returns a string representation of the user. * * @return A string representation of the user. */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append( "WrapperUNIXUser[" ); sb.append( getUID() ); sb.append( ", " ); sb.append( getGID() ); sb.append( ", " ); sb.append( getUser() ); sb.append( ", " ); sb.append( getRealName() ); sb.append( ", " ); sb.append( getHome() ); sb.append( ", " ); sb.append( getShell() ); sb.append( ", groups {" ); WrapperGroup[] groups = getGroups(); for ( int i = 0; i < groups.length; i++ ) { if ( i > 0 ) { sb.append( ", " ); } sb.append( groups[i].toString() ); } sb.append( "}" ); sb.append( "]" ); return sb.toString(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperUser.java100644 0 0 4113 12440202301 23501 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.util.ArrayList; import java.util.List; /** * A WrapperUser contains information about a user account on the platform * running the Wrapper. A WrapperUser is obtained by calling * WrapperManager.getUser() or WrapperManager.getInteractiveUser(). * * @author Leif Mortenson */ public abstract class WrapperUser { /* The name of the user. */ private String m_user; /** A list of the groups that this user is registered with. */ private List m_groups = new ArrayList(); /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ WrapperUser( String user ) { // Decode the parameters using the default system encoding. m_user = user; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the name of the user. * * @return The name of the user. */ public String getUser() { return m_user; } /** * Adds a group to the user. * * @param group WrapperGroup to be added. */ void addGroup( WrapperGroup group ) { m_groups.add( group ); } /** * Returns an array of WrapperGroup instances which define the groups that * the user belongs to. * * @return An array of WrapperGroups. */ public WrapperGroup[] getGroups() { WrapperGroup[] groups = new WrapperGroup[m_groups.size()]; m_groups.toArray( groups ); return groups; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperWin32Group.java100644 0 0 4022 12440202301 24501 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * A WrapperGroup contains information about a group which a user * belongs to. A WrapperGroup is obtained via a WrapperUser. * * @author Leif Mortenson */ public class WrapperWin32Group extends WrapperGroup { /** The current SID of the Group. */ private String m_sid; /** The domain of the User Account. */ private String m_domain; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ WrapperWin32Group( String sid, String user, String domain ) { super( user ); // Decode the parameters using the default system encoding. m_sid = sid; m_domain = domain; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the current Security Identifier (SID) of the user account. * * @return The SID of the user account. */ public String getSID() { return m_sid; } /** * Returns the domain name of the user account. * * @return The domain name of the user account. */ public String getDomain() { return m_domain; } /** * Returns the full name of the group. * * @return The full name of the group. */ public String getAccount() { return m_domain + "/" + getGroup(); } public String toString() { return "WrapperWin32Group[" + getAccount() + "]"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperWin32Service.java100644 0 0 10510 12440202301 25024 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * A WrapperWin32Service contains information about an individual service * registered with the current system. * * @author Leif Mortenson */ public class WrapperWin32Service { public static final int SERVICE_STATE_STOPPED = 0x00000001; public static final int SERVICE_STATE_START_PENDING = 0x00000002; public static final int SERVICE_STATE_STOP_PENDING = 0x00000003; public static final int SERVICE_STATE_RUNNING = 0x00000004; public static final int SERVICE_STATE_CONTINUE_PENDING = 0x00000005; public static final int SERVICE_STATE_PAUSE_PENDING = 0x00000006; public static final int SERVICE_STATE_PAUSED = 0x00000007; /** The name of the service. */ private String m_name; /** The display name of the service. */ private String m_displayName; /** The last known state of the service. */ private int m_serviceState; /** The exit of the service. */ private int m_exitCode; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ WrapperWin32Service( String name, String displayName, int serviceState, int exitCode ) { // Decode the parameters using the default system encoding. m_name = name; m_displayName = displayName; m_serviceState = serviceState; m_exitCode = exitCode; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the name of the service. * * @return The name of the service. */ public String getName() { return m_name; } /** * Returns the display name of the service. * * @return The display name of the service. */ public String getDisplayName() { return m_displayName; } /** * Returns the last known state name of the service. * * @return The last known state name of the service. */ public String getServiceStateName() { int serviceState = getServiceState(); switch( serviceState ) { case SERVICE_STATE_STOPPED: return "STOPPED"; case SERVICE_STATE_START_PENDING: return "START_PENDING"; case SERVICE_STATE_STOP_PENDING: return "STOP_PENDING"; case SERVICE_STATE_RUNNING: return "RUNNING"; case SERVICE_STATE_CONTINUE_PENDING: return "CONTINUE_PENDING"; case SERVICE_STATE_PAUSE_PENDING: return "PAUSE_PENDING"; case SERVICE_STATE_PAUSED: return "PAUSED"; default: return "UNKNOWN(" + serviceState + ")"; } } /** * Returns the last known state of the service. * * @return The last known state of the service. */ public int getServiceState() { return m_serviceState; } /** * Returns the exit of the service, or 0 if it is still running. * * @return The exit of the service. */ public int getExitCode() { return m_exitCode; } /** * Returns a string representation of the user. * * @return A string representation of the user. */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append( "WrapperWin32Service[name=\"" ); sb.append( getName() ); sb.append( "\", displayName=\"" ); sb.append( getDisplayName() ); sb.append( "\", state=" ); sb.append( getServiceStateName() ); sb.append( ", exitCode=" ); sb.append( getExitCode() ); sb.append( "]" ); return sb.toString(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/WrapperWin32User.java100644 0 0 6604 12440202301 24333 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.util.Date; /** * A WrapperUser contains information about a user account on the platform * running the Wrapper. A WrapperUser is obtained by calling * WrapperManager.getUser() or WrapperManager.getInteractiveUser(). * * @author Leif Mortenson */ public class WrapperWin32User extends WrapperUser { /** The current SID of the User Account. */ private String m_sid; /** The domain of the User Account. */ private String m_domain; /** Time that the user logged in. */ private long m_loginTime; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ WrapperWin32User( String sid, String user, String domain, int loginTime) { super( user ); // Decode the parameters using the default system encoding. m_sid = sid; m_domain = domain; // Convert the login time to milliseconds. m_loginTime = loginTime * 1000L; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the current Security Identifier (SID) of the user account. * * @return The SID of the user account. */ public String getSID() { return m_sid; } /** * Returns the domain name of the user account. * * @return The domain name of the user account. */ public String getDomain() { return m_domain; } /** * Returns the full name of the user account. * * @return The full name of the user account. */ public String getAccount() { return m_domain + "/" + getUser(); } /** * Returns the login time of the user account. * * @return The login time of the user account. */ public long getLoginTime() { return m_loginTime; } /** * Called by native code to add a Group to the User. */ private void addGroup( String sid, String user, String domain ) { addGroup( new WrapperWin32Group( sid, user, domain ) ); } /** * Returns a string representation of the user. * * @return A string representation of the user. */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append( "WrapperWin32User[" ); sb.append( getAccount() ); sb.append( ", " ); sb.append( new Date( m_loginTime ).toString() ); sb.append( ", groups {" ); WrapperGroup[] groups = getGroups(); for ( int i = 0; i < groups.length; i++ ) { if ( i > 0 ) { sb.append( ", " ); } sb.append( groups[i].toString() ); } sb.append( "}" ); sb.append( "]" ); return sb.toString(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/AboutDialog.java100644 0 0 10433 12440202301 24362 0ustar 0 0 package org.tanukisoftware.wrapper.demo; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.awt.Color; import java.awt.Cursor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.IOException; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.test.Main; public class AboutDialog extends JDialog { private static final long serialVersionUID = 1L; public AboutDialog( JFrame parent ) { super( parent, DemoApp.getRes().getString("About Dialog"), true ); JPanel main = new JPanel(); main.setBorder( new EmptyBorder( 10, 20, 10, 20 ) ); this.setResizable( false ); Box b = Box.createVerticalBox(); b.add( Box.createGlue() ); b.add( new JLabel( DemoApp.getRes().getString("Demo Application for the Java Service Wrapper" ) ) ); b.add( new JLabel( "By Tanuki Software Ltd." ) ); final JLabel url = new JLabel(); url.setText( "http://wrapper.tanukisoftware.com" ); url.setForeground( Color.BLUE ); url.addMouseListener( new MouseListener() { public void mouseReleased( MouseEvent e ) { // TODO Auto-generated method stub } public void mousePressed( MouseEvent e ) { // TODO Auto-generated method stub } public void mouseExited( MouseEvent e ) { url.setCursor( new Cursor( Cursor.DEFAULT_CURSOR ) ); } public void mouseEntered( MouseEvent e ) { url.setCursor( new Cursor( Cursor.HAND_CURSOR ) ); } public void mouseClicked( MouseEvent e ) { if ( e.getClickCount() > 0 ) { String url = "http://wrapper.tanukisoftware.com"; String cmd; if ( WrapperManager.isWindows() ) { cmd = "cmd.exe /c start " + url; } else if ( WrapperManager.isMacOSX() ) { cmd = "open " + url; } else { cmd = "firefox " + url; } try { Runtime.getRuntime().exec( cmd ); } catch ( IOException ex ) { System.out.println( DemoApp.getRes().getString( "Failed to launch external browser to view web page using command:" ) ); System.out.println( " " + cmd ); System.out.println( DemoApp.getRes().getString(" Error: ") + ex.getMessage() ); System.out.println(); System.out.println( DemoApp.getRes().getString( "Please enter URL into your browser: " ) + url ); System.out.println(); } } } } ); b.add( url ); b.add( Box.createGlue() ); main.add( b, "Center" ); JPanel p2 = new JPanel(); JButton ok = new JButton( "Ok " ); p2.add( ok ); main.add( p2, "South" ); ok.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent evt ) { setVisible( false ); } } ); getContentPane().add( main, "Center" ); this.setLocation( this.getParent().getLocation() ); this.pack(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/CustomizeDialog.java100644 0 0 34422 12440202301 25276 0ustar 0 0 package org.tanukisoftware.wrapper.demo; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JTextField; import javax.swing.filechooser.FileFilter; import org.tanukisoftware.wrapper.demo.ExtensionFilter; ; class CustomizeDialog extends JDialog { /** * */ private static final long serialVersionUID = -5258541969990785046L; private JPanel jPanel1; private JLabel jLabel1, jLabel2, jLabel3; private JButton jButton1, jButton2, jButton3, jButton4, jButton5; private JTextField jTextField1, jTextField2, jTextField3; private JSeparator jSeparator1; private String selectedSource, selectedIcon, selectedSplashScreen, selectedDestination; private int result; public int getResult() { return result; } public String getSelectedSource() { return selectedSource; } public String getSelectedIcon() { return selectedIcon; } public String getSelectedSplashScreen() { return selectedSplashScreen; } public String getSelectedDestination() { return selectedDestination; } protected CustomizeDialog() { super(); java.awt.GridBagConstraints gridBagConstraints; jPanel1 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); jButton3 = new javax.swing.JButton(); jButton4 = new javax.swing.JButton(); jButton5 = new javax.swing.JButton(); jTextField1 = new javax.swing.JTextField(); jTextField2 = new javax.swing.JTextField(); jTextField3 = new javax.swing.JTextField(); jSeparator1 = new javax.swing.JSeparator(); setDefaultCloseOperation( javax.swing.WindowConstants.HIDE_ON_CLOSE ); this.getContentPane().setLayout( new java.awt.GridBagLayout() ); this.setTitle( DemoApp.getRes().getString( "Wrapper DemoApp: Customize" ) ); jPanel1.setLayout( new java.awt.GridBagLayout() ); jLabel1.setHorizontalAlignment( javax.swing.SwingConstants.RIGHT ); jLabel1.setText( DemoApp.getRes().getString( "Source Binary" ) ); jPanel1.add( jLabel1, new java.awt.GridBagConstraints() ); jLabel2.setHorizontalAlignment( javax.swing.SwingConstants.RIGHT ); jLabel2.setText( DemoApp.getRes().getString( "Icon" ) ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; jPanel1.add( jLabel2, gridBagConstraints ); jLabel3.setText( DemoApp.getRes().getString( "Splash screen" ) ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; jPanel1.add( jLabel3, gridBagConstraints ); jButton1.setText( "..." ); jButton1.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { JFileChooser fd = new JFileChooser(); fd.setMultiSelectionEnabled( false ); fd.setCurrentDirectory( new File( "." ) ); fd.setDialogTitle( DemoApp.getRes().getString( "Select Executable for customization" ) ); fd.setFileHidingEnabled( true ); fd.setApproveButtonText( DemoApp.getRes().getString( "Load Executable" ) ); FileFilter filter = new ExtensionFilter( DemoApp.getRes().getString( "Wrapper Executable (*.exe)" ), new String[] { "exe" } ); fd.setFileFilter( filter ); int returnVal = fd.showOpenDialog( CustomizeDialog.this ); if ( returnVal == JFileChooser.APPROVE_OPTION ) { try { selectedSource = fd.getSelectedFile().getCanonicalPath(); jTextField1.setText( selectedSource ); } catch ( IOException e1 ) { // TODO Auto-generated catch block e1.printStackTrace(); } } } } ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; jPanel1.add( jButton1, gridBagConstraints ); jButton2.setText( "..." ); jButton2.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { JFileChooser fd = new JFileChooser(); fd.setMultiSelectionEnabled( false ); fd.setCurrentDirectory( new File( "." ) ); fd.setDialogTitle( DemoApp.getRes().getString( "Select Icon for customization" ) ); fd.setFileHidingEnabled( true ); fd.setApproveButtonText( DemoApp.getRes().getString( "Load Icon" ) ); FileFilter filter = new ExtensionFilter( DemoApp.getRes().getString( "Icon File (*.ico)" ), new String[] { "ico" } ); fd.setFileFilter( filter ); int returnVal = fd.showOpenDialog( CustomizeDialog.this ); if ( returnVal == JFileChooser.APPROVE_OPTION ) { try { selectedIcon = fd.getSelectedFile().getCanonicalPath(); jTextField2.setText( selectedIcon ); } catch ( IOException e1 ) { // TODO Auto-generated catch block e1.printStackTrace(); } } } } ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; jPanel1.add( jButton2, gridBagConstraints ); jButton3.setText( "..." ); jButton3.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { JFileChooser fd = new JFileChooser(); fd.setMultiSelectionEnabled( false ); fd.setCurrentDirectory( new File( "." ) ); fd.setDialogTitle( DemoApp.getRes().getString( "Select splash screen for customization" ) ); fd.setFileHidingEnabled( true ); fd.setApproveButtonText( DemoApp.getRes().getString( "Load splash screen" ) ); FileFilter filter = new ExtensionFilter( DemoApp.getRes().getString( "Splash screen File (*.bmp)" ), new String[] { "bmp" } ); fd.setFileFilter( filter ); int returnVal = fd.showOpenDialog( CustomizeDialog.this ); if ( returnVal == JFileChooser.APPROVE_OPTION ) { try { selectedSplashScreen = fd.getSelectedFile().getCanonicalPath(); jTextField3.setText( selectedSplashScreen ); } catch ( IOException e1 ) { // TODO Auto-generated catch block e1.printStackTrace(); } } } } ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; jPanel1.add( jButton3, gridBagConstraints ); jButton4.setText( DemoApp.getRes().getString( "Customize" ) ); jButton4.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { String errorMsg = ""; if ( jTextField1.getText().length() == 0 || !new File( jTextField1.getText() ).exists() ) { jTextField1.setBackground( Color.red ); errorMsg = errorMsg.concat( DemoApp.getRes().getString( "No valid Source Binary Specified\n" ) ); } if ( jTextField2.getText().length() != 0 && !new File( jTextField2.getText() ).exists() ) { jTextField2.setBackground( Color.red ); errorMsg = errorMsg.concat( DemoApp.getRes().getString( "No valid Icon File Specified\n" ) ); } if ( jTextField3.getText().length() != 0 && !new File( jTextField3.getText() ).exists() ) { jTextField3.setBackground( Color.red ); errorMsg = errorMsg.concat( DemoApp.getRes().getString( "No valid Splash Screen File Specified\n" ) ); } if ( jTextField2.getText().length() == 0 && jTextField3.getText().length() == 0 ) { errorMsg = errorMsg.concat( DemoApp.getRes().getString( "Please select at least one Icon or Splash Screen File.\n" ) ); jTextField2.setBackground( Color.yellow ); jTextField3.setBackground( Color.yellow ); } if ( errorMsg.length() > 0 ) { JOptionPane.showMessageDialog( CustomizeDialog.this, DemoApp.getRes().getString( "See the following list of errors:\n" ) + errorMsg, DemoApp.getRes().getString( "Error" ), JOptionPane.ERROR_MESSAGE ); return; } JFileChooser fd = new JFileChooser(); fd.setMultiSelectionEnabled( false ); fd.setCurrentDirectory( new File( "." ) ); fd.setDialogTitle( DemoApp.getRes().getString( "Select destination file of the customization" ) ); fd.setFileHidingEnabled( true ); fd.setApproveButtonText( DemoApp.getRes().getString( "Custimize Binary" ) ); FileFilter filter = new ExtensionFilter( DemoApp.getRes().getString( "Executable File (*.exe)" ), new String[] { "exe" } ); fd.setFileFilter( filter ); int returnVal = fd.showSaveDialog( CustomizeDialog.this ); if ( returnVal == JFileChooser.APPROVE_OPTION ) { try { selectedDestination = fd.getSelectedFile().getCanonicalPath(); if ( !selectedDestination.toLowerCase().endsWith( ".exe" ) ) { selectedDestination = selectedDestination.concat( ".exe" ); } if ( selectedDestination.equals( jTextField1.getText() ) ) { JOptionPane.showMessageDialog( CustomizeDialog.this, DemoApp.getRes().getString( "You cannot set the Source and Destination to the same File" ), DemoApp.getRes().getString( "Error" ), JOptionPane.ERROR_MESSAGE ); selectedDestination = ""; } else { result = 1; CustomizeDialog.this.setVisible( false ); } } catch ( IOException ex ) { ex.printStackTrace(); } } } } ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; jPanel1.add( jButton4, gridBagConstraints ); jButton5.setText( "Cancel" ); jButton5.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { result = 0; CustomizeDialog.this.setVisible( false ); } } ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; jPanel1.add( jButton5, gridBagConstraints ); jTextField1.setColumns( 20 ); jTextField1.setToolTipText( "" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; jPanel1.add( jTextField1, gridBagConstraints ); jTextField2.setColumns( 20 ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; jPanel1.add( jTextField2, gridBagConstraints ); jTextField3.setColumns( 20 ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; jPanel1.add( jTextField3, gridBagConstraints ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; jPanel1.add( jSeparator1, gridBagConstraints ); this.getContentPane().add( jPanel1, new java.awt.GridBagConstraints() ); this.setLocation( this.getParent().getLocation() ); this.setResizable( false ); this.setModal( true ); this.pack(); pack(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/DeadLock.java100644 0 0 5345 12440202301 23624 0ustar 0 0 package org.tanukisoftware.wrapper.demo; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ public class DeadLock { private int m_id; private Object m_obj1; private Object m_obj2; protected DeadLock( int id, Object obj1, Object obj2 ) { m_id = id; m_obj1 = obj1; m_obj2 = obj2; Thread runner = new Thread( "Locker-" + m_id ) { public void run() { System.out.println( DemoApp.getRes().getString( "Locker-{0}: Started", new Integer( m_id ) ) ); try { lockFirst(); } catch ( Throwable t ) { t.printStackTrace(); } System.out.println( DemoApp.getRes().getString( "Locker-{0}: Complete", new Integer( m_id ) ) ); } }; runner.start(); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ private void lockSecond() { System.out.println( DemoApp.getRes().getString( "Locker-{0}: Try locking {1}...", new Integer( m_id ), m_obj2.toString() ) ); synchronized ( m_obj2 ) { System.out.println( DemoApp.getRes().getString( "Locker-{0}: Oops! Locked {1}", new Integer( m_id ), m_obj2.toString() ) ); } } public void create3ObjectDeadlock() { Object obj1 = new Object(); Object obj2 = new Object(); Object obj3 = new Object(); new DeadLock( 1, obj1, obj2 ); new DeadLock( 2, obj2, obj3 ); new DeadLock( 3, obj3, obj1 ); } public void create2ObjectDeadlock() { Object obj1 = new Object(); Object obj2 = new Object(); new DeadLock( 1, obj1, obj2 ); new DeadLock( 2, obj2, obj1 ); } private void lockFirst() { System.out.println( DemoApp.getRes().getString( "Locker-{0}: Locking {1}...", new Integer( m_id ), m_obj1.toString() ) ); synchronized ( m_obj1 ) { System.out.println( DemoApp.getRes().getString( "Locker-{0}: Locked {1}", new Integer( m_id ), m_obj1.toString() ) ); try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } lockSecond(); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/DemoApp.java100644 0 0 100556 12440202301 23543 0ustar 0 0 package org.tanukisoftware.wrapper.demo; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.awt.Color; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import javax.swing.JOptionPane; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import org.tanukisoftware.wrapper.WrapperActionServer; import org.tanukisoftware.wrapper.WrapperJNIError; import org.tanukisoftware.wrapper.WrapperLicenseError; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperListener; import org.tanukisoftware.wrapper.WrapperProcessConfig; import org.tanukisoftware.wrapper.WrapperResources; import org.tanukisoftware.wrapper.WrapperSystemPropertyUtil; /** * This is a Test / Example program which can be used to test the main features * of the Wrapper. *

* It is also an example of Integration Method #3, where you implement the * WrapperListener interface manually. *

* NOTE that in most cases you will want to use Method #1, using the * WrapperSimpleApp helper class to integrate your application. Please see the * * integration section of the documentation for more details. * * @author Leif Mortenson */ public class DemoApp implements WrapperListener { private WrapperActionServer m_actionServer; private static DemoAppMainFrame m_frame; private static boolean m_isTestCaseRunning; private static Process m_testCase; private static PrintStream m_childPrintStream; private static WrapperResources m_res; private String m_confFile; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ private DemoApp() { m_isTestCaseRunning = false; m_confFile = "../conf/demoapp.conf"; } protected DemoAppMainFrame getFrame() { return m_frame; } protected void setTestCaseRunning( boolean val ) { m_isTestCaseRunning = val; } protected boolean isTestCaseRunning() { return m_isTestCaseRunning; } public static WrapperResources getRes() { if ( m_res == null ) { // Synchronize and then recheck to avoid this method always synchronizing. synchronized( DemoApp.class ) { if ( m_res == null ) { m_res = WrapperManager.loadWrapperResources( "wrapperTestApp", WrapperSystemPropertyUtil.getStringProperty( "wrapper.lang.folder", "../lang" ) ); } } } return m_res; } /*--------------------------------------------------------------- * Inner Classes *-------------------------------------------------------------*/ /*--------------------------------------------------------------- * WrapperListener Methods *-------------------------------------------------------------*/ public void controlEvent( int event ) { System.out.println( getRes().getString( "TestWrapper: controlEvent({0})", new Integer( event ) ) ); if ( event == WrapperManager.WRAPPER_CTRL_LOGOFF_EVENT ) { if ( WrapperManager.isLaunchedAsService() || WrapperManager.isIgnoreUserLogoffs() ) { System.out.println( getRes().getString( "TestWrapper: Ignoring logoff event" ) ); // Ignore } else { WrapperManager.stop( 0 ); } } else if ( event == WrapperManager.WRAPPER_CTRL_C_EVENT ) { // WrapperManager.stop(0); // May be called before the runner is started. } else { WrapperManager.stop( 0 ); } } public Integer start( String[] args ) { String command; if ( args.length <= 0 ) { command = "dialog"; } else { command = args[0]; } if ( command.equals( "dialog" ) ) { System.out.println( "Demo: start()" ); System.out.println( getRes().getString( "Demo: Showing dialog..." ) ); try { m_frame = new DemoAppMainFrame( this ); m_frame.setVisible( true ); try { m_testCase = this.callAction( "start" ); } catch ( IOException e ) { // TODO Auto-generated catch block e.printStackTrace(); } } catch ( java.lang.InternalError e ) { System.out.println( getRes().getString( "Demo: " ) ); System.out.println( getRes().getString( "Demo: ERROR - Unable to display the GUI:" ) ); System.out.println( "Demo: " + e.toString() ); System.out.println( "Demo: " ); System.out.println( getRes().getString( "Demo: This demo requires a display to show its GUI. Exiting..." ) ); command = "console"; } catch ( java.awt.AWTError e ) { System.out.println( "Demo: " ); System.out.println( getRes().getString( "Demo: ERROR - Unable to display the GUI:" ) ); System.out.println( "Demo: " + e.toString() ); System.out.println( "Demo: " ); System.out.println( getRes().getString( "Demo: This demo requires a display to show its GUI. Exiting..." ) ); command = "console"; } catch ( java.lang.UnsupportedOperationException e ) { // java.awt.HeadlessException does not exist in Java versions // prior to 1.4 if ( e.getClass().getName().equals( "java.awt.HeadlessException" ) ) { System.out.println( "Demo: " ); System.out.println( getRes().getString( "Demo: ERROR - Unable to display the GUI:" ) ); System.out.println( "Demo: " + e.toString() ); System.out.println( "Demo: " ); System.out.println( getRes().getString( "Demo: This demo requires a display to show its GUI. Exiting..." ) ); command = "console"; } else { throw e; } } } else if ( command.equals( "start" ) ) { Thread commandRunner = new Thread( "DemoApp-Command-Runner" ) { public void run() { BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) ); String command = ""; System.out.println( getRes().getString( "Started and waiting for a command from the Demo Application" ) ); while ( command.compareToIgnoreCase( "finish" ) != 0 ) { try { command = br.readLine(); System.out.println( getRes().getString( "Read action: {0}", command ) ); if ( command.equals( "crash" ) ) { Thread.sleep( 5000 ); System.out.println( getRes().getString( "Going to cause the JVM to crash." ) ); WrapperManager.accessViolationNative(); } else if ( command.equals( "frozen" ) ) { WrapperManager.appearHung(); System.out.println( getRes().getString( "Waiting until wrapper stops this JVM." ) ); while ( true ) { } } else if ( command.equals( "out_of_mem" ) ) { int ii = 5 - 3; System.out.println( getRes().getString( "Going to cause a Out of Memory Error" ) ); Thread.sleep( 5000 ); // System.out.println("got java.lang.OutOfMemoryError"); if ( 5 > ii ) { getOutOfMemError(); } System.out.println( getRes().getString( "Application should get restarted now..." ) ); try { Thread.sleep( 5000 ); } catch ( InterruptedException e ) { // TODO Auto-generated catch block e.printStackTrace(); } } else if ( command.equals( "deadlock" ) ) { if ( WrapperManager.isStandardEdition() ) { System.out.println( getRes().getString( "Deadlock Tester Running..." ) ); Object obj1 = new Object(); Object obj2 = new Object(); int exitCode = 1; DeadLock dl = new DeadLock( 1, obj1, obj2 ); switch ( exitCode ) { case 1: System.out.println( getRes().getString( "2-object deadlock." ) ); dl.create2ObjectDeadlock(); break; case 2: System.out.println( getRes().getString( "Wait then 2-object deadlock." ) ); try { Thread.sleep( 10000 ); } catch ( InterruptedException e ) { } dl.create2ObjectDeadlock(); break; case 3: System.out.println( getRes().getString( "3-object deadlock." ) ); dl.create3ObjectDeadlock(); break; default: System.out.println( getRes().getString( "Done." ) ); } // Always wait a couple seconds to make sure the above // threads have time to start. try { System.out.println( getRes().getString( "Sleeping for 5 sec..." ) ); Thread.sleep( 5000 ); } catch ( InterruptedException e ) { } System.out.println( getRes().getString( "Main Complete." ) ); } else { System.out.println( getRes().getString( "Deadlock checks require at least the Standard Edition." ) ); } } else if ( command.indexOf( "exec" ) == 0 ) { try { String input = command.substring(5); System.out.println( getRes().getString( "Starting a simple application: " ) + input ); if ( input != null && input.length() > 0 ) { WrapperManager.exec( input, new WrapperProcessConfig().setDetached( false ) ); System.out.println( getRes().getString( "Successfully executed!") ); } } catch ( SecurityException e ) { e.printStackTrace(); } catch ( NullPointerException e ) { e.printStackTrace(); } catch ( IllegalArgumentException e ) { e.printStackTrace(); } catch ( UnsatisfiedLinkError e ) { e.printStackTrace(); } catch ( IOException e ) { e.printStackTrace(); } catch ( WrapperJNIError e ) { e.printStackTrace(); } catch ( WrapperLicenseError e ) { e.printStackTrace(); } } } catch ( IOException e ) { // TODO Auto-generated catch block e.printStackTrace(); } catch ( InterruptedException e ) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; commandRunner.start(); } return null; } public int stop( int exitCode ) { System.out.println( "Demo: stop(" + exitCode + ")" ); if ( m_actionServer != null ) { try { m_actionServer.stop(); } catch ( Exception e ) { System.out.println( getRes().getString( "Demo: Unable to stop the action server: {0}", e.getMessage() ) ); } } if ( m_frame != null ) { if ( !WrapperManager.hasShutdownHookBeenTriggered() ) { m_frame.setVisible( false ); m_frame.dispose(); } m_frame = null; } return exitCode; } private Process callAction( String action ) throws IOException { Process p = null; if ( action.equals( "mail" ) ) { MailDialog md = new MailDialog(); md.setVisible( true ); if ( md.getResult() != 0 ) { callAction( "finish" ); try { Thread.sleep( 3000 ); if ( m_isTestCaseRunning ) { System.out.println( getRes().getString( "destroy!" ) ); m_testCase.destroy(); } } catch ( InterruptedException e ) { // TODO Auto-generated catch block e.printStackTrace(); } String wrapperBin; if ( WrapperManager.isWindows() ) { wrapperBin = "../bin/wrapper.exe"; } else { wrapperBin = "../bin/wrapper"; } String arg = wrapperBin + " -c " + m_confFile + " wrapper.console.flush=TRUE wrapper.console.format=LPM wrapper.app.parameter.1=start " + md.getEvents() + " wrapper.event.default.email.debug=TRUE wrapper.event.default.email.smtp.host=" + md.getServer() + " wrapper.event.default.email.smtp.port=" + md.getPort() + " wrapper.event.default.email.sender=" + md.getSender() + " wrapper.event.default.email.recipient=" + md.getRecipients(); // System.out.println( "execing: " + arg ); p = Runtime.getRuntime().exec( arg ); m_childPrintStream = new PrintStream( p.getOutputStream() ); if ( p != null ) { m_frame.jTabbedPane2.setSelectedIndex( 1 ); m_isTestCaseRunning = true; BufferedReader br = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); Runnable setTextRun = new LoggerThread( br, this ); Thread t = new Thread( setTextRun ); t.start(); // return true; } } } else if ( action.equals( "daemon" ) ) { System.out.println( getRes().getString( "Going to install an application as daemon - this requires root privileges" ) ); p = Runtime.getRuntime().exec( " ../bin/testwrapper install" ); if ( p != null ) { m_frame.jTabbedPane2.setSelectedIndex( 1 ); BufferedReader br = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); Runnable setTextRun = new LoggerThread( br, this, true ); Thread t = new Thread( setTextRun ); t.start(); try { p.waitFor(); } catch ( InterruptedException e ) { // TODO Auto-generated catch block e.printStackTrace(); } p = null; p = Runtime.getRuntime().exec( "../bin/testwrapper remove" ); if ( p != null ) { m_frame.jTabbedPane2.setSelectedIndex( 1 ); BufferedReader br2 = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); Runnable setTextRun2 = new LoggerThread( br2, this, true ); Thread t2 = new Thread( setTextRun2 ); t2.start(); try { p.waitFor(); } catch ( InterruptedException e ) { // TODO Auto-generated catch block e.printStackTrace(); } // return true; } } p = null; // WrapperManager.exec( "sudo ../test/demoapp remove" ); } else if ( action.equals( "service" ) ) { p = Runtime.getRuntime().exec( "..\\bin\\wrapper.exe -it " + m_confFile + " wrapper.console.flush=TRUE" ); // WrapperManager.exec( "sudo ../test/demoapp remove" ); if ( p != null ) { m_frame.jTabbedPane2.setSelectedIndex( 1 ); BufferedReader br = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); Runnable setTextRun = new LoggerThread( br, this, true ); Thread t = new Thread( setTextRun ); t.start(); // return true; } p = null; } else if ( action.equals( "customize" ) ) { CustomizeDialog cd = new CustomizeDialog(); cd.setVisible( true ); if ( cd.getResult() == 1 ) { String arg = "\"" + cd.getSelectedSource() + "\"" + " --customize --target \"" + cd.getSelectedDestination() + "\""; if ( cd.getSelectedIcon() != null && cd.getSelectedIcon().length() > 0 ) { arg = arg.concat( " --icon \"" + cd.getSelectedIcon() + "\"" ); } if ( cd.getSelectedSplashScreen() != null && cd.getSelectedSplashScreen().length() > 0 ) { arg = arg.concat( " --splash \"" + cd.getSelectedSplashScreen() + "\"" ); } p = Runtime.getRuntime().exec( arg ); if ( p != null ) { m_frame.jTabbedPane2.setSelectedIndex( 1 ); BufferedReader br = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); Runnable setTextRun = new LoggerThread( br, this, true); Thread t = new Thread( setTextRun ); t.start(); // return true; } p = null; } } else if ( action.equals( "start" ) ) { String wrapperBin; if ( WrapperManager.isWindows() ) { wrapperBin = "../bin/wrapper.exe"; } else { wrapperBin = "../bin/wrapper"; } String arg = wrapperBin + " -c " + m_confFile + " wrapper.console.flush=TRUE wrapper.console.format=LPM wrapper.app.parameter.1=" + action; // System.out.println( "calling: " + arg ); if ( !m_isTestCaseRunning ) { // System.out.println( "execing: " + arg ); p = Runtime.getRuntime().exec( arg ); m_childPrintStream = new PrintStream( p.getOutputStream() ); } if ( p != null ) { m_frame.jTabbedPane2.setSelectedIndex( 1 ); m_isTestCaseRunning = true; BufferedReader br = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); Runnable setTextRun = new LoggerThread( br, this ); Thread t = new Thread( setTextRun ); t.start(); } // ps.close(); } else if ( action.equals( "finish" ) ) { if ( m_isTestCaseRunning ) { m_childPrintStream.println( action ); m_childPrintStream.flush(); m_childPrintStream.close(); // ps.close(); } } else if ( action.equals( "exec" ) ) { String input = ""; if ( System.getProperty( "os.name" ).indexOf( "Windows" ) >= 0 ) { input = ( String )JOptionPane.showInputDialog( m_frame, getRes().getString( "Please enter the Command, you wish to execute:" ), getRes().getString( "Child Process Execution" ), JOptionPane.QUESTION_MESSAGE, null, null, ( Object )"notepad" ); } else { input = ( String )JOptionPane.showInputDialog( m_frame, getRes().getString( "Please enter the Command, you wish to execute:" ), getRes().getString( "Child Process Execution" ), JOptionPane.QUESTION_MESSAGE, null, null, ( Object )"xclock" ); } if ( input != null && input.length() > 0 ) { String wrapperBin; if ( WrapperManager.isWindows() ) { wrapperBin = "../bin/wrapper.exe"; } else { wrapperBin = "../bin/wrapper"; } String arg = wrapperBin + " -c " + m_confFile + " wrapper.console.flush=TRUE wrapper.console.format=LPM wrapper.app.parameter.1=start"; //System.out.println( "calling: " + arg ); if ( !m_isTestCaseRunning ) { p = Runtime.getRuntime().exec( arg ); m_childPrintStream = new PrintStream( p.getOutputStream() ); DemoApp.m_frame.getJMenuBar().getMenu( 0 ).getItem( 0 ).setEnabled( false ); DemoApp.m_frame.getJMenuBar().getMenu( 0 ).getItem( 1 ).setEnabled( true ); } if ( p != null ) { m_frame.jTabbedPane2.setSelectedIndex( 1 ); m_isTestCaseRunning = true; BufferedReader br = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); Runnable setTextRun = new LoggerThread( br, this ); Thread t = new Thread( setTextRun ); t.start(); // return true; } m_childPrintStream.println( action + " " + input); m_childPrintStream.flush(); } } else { String wrapperBin; if ( WrapperManager.isWindows() ) { wrapperBin = "../bin/wrapper.exe"; } else { wrapperBin = "../bin/wrapper"; } String arg = wrapperBin + " -c " + m_confFile + " wrapper.console.flush=TRUE wrapper.console.format=LPM wrapper.app.parameter.1=start"; //System.out.println( "calling: " + arg ); if ( !m_isTestCaseRunning ) { p = Runtime.getRuntime().exec( arg ); m_childPrintStream = new PrintStream( p.getOutputStream() ); DemoApp.m_frame.getJMenuBar().getMenu( 0 ).getItem( 0 ).setEnabled( false ); DemoApp.m_frame.getJMenuBar().getMenu( 0 ).getItem( 1 ).setEnabled( true ); } if ( p != null ) { m_frame.jTabbedPane2.setSelectedIndex( 1 ); m_isTestCaseRunning = true; BufferedReader br = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); Runnable setTextRun = new LoggerThread( br, this ); Thread t = new Thread( setTextRun ); t.start(); // return true; } m_childPrintStream.println( action ); m_childPrintStream.flush(); // ps.close(); } return p == null ? m_testCase : p; } /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ protected boolean doAction( String action ) { //System.out.println( "doAction " + action ); try { m_testCase = this.callAction( action ); } catch ( IOException e ) { // TODO Auto-generated catch block e.printStackTrace(); } return false; } static void getOutOfMemError() { try { throw new java.lang.OutOfMemoryError( getRes().getString( "BANG" ) ); } catch ( OutOfMemoryError e ) { e.printStackTrace(); } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ /** * IMPORTANT: Please read the Javadocs for this class at the top of the page * before you start to use this class as a template for integrating your own * application. This will save you a lot of time. */ public static void main( String[] args ) { System.out.println( getRes().getString( "DemoApp: Initializing..." ) ); WrapperManager.start( ( new DemoApp() ), args ); } } class LoggerThread implements Runnable { BufferedReader br; DemoApp m_this; boolean optional; public LoggerThread( BufferedReader br, DemoApp m_this ) { this.br = br; this.m_this = m_this; this.optional = false; } public LoggerThread( BufferedReader br, DemoApp m_this, boolean optional ) { this.br = br; this.m_this = m_this; this.optional = optional; } public void run() { try { String str; int j = 0; if ( !optional ) { m_this.getFrame().getlogTextArea().getDocument().remove( 0, m_this.getFrame().getlogTextArea().getDocument().getLength() ); } while ( ( str = br.readLine() ) != null ) { if ( j++ > 0 && !str.equals( "" ) ) { if ( m_this != null && m_this.getFrame() != null ) { SimpleAttributeSet sas = new SimpleAttributeSet(); String insString = getStyle( str, sas ); m_this.getFrame().getlogTextArea().getDocument().insertString( m_this.getFrame().getlogTextArea().getDocument().getEndPosition().getOffset() - 1, insString + "\n", sas ); int p1 = m_this.getFrame().getlogTextArea().getDocument().getLength(); m_this.getFrame().getlogTextArea().setCaretPosition( p1 ); } } } if (!optional) { m_this.setTestCaseRunning( false ); } } catch ( Exception x ) { x.printStackTrace(); } } private String getStyle( String insString, SimpleAttributeSet sas ) { String returnVal = insString; StyleConstants.setFontFamily( sas, "monospaced" ); StyleConstants.setFontSize( sas, 12 ); StyleConstants.setBold( sas, true ); if ( insString.indexOf( "STATUS |" ) >= 0 || insString.indexOf( "NOTICE |" ) >= 0) { StyleConstants.setForeground( sas, Color.black ); returnVal = insString.substring( 9 ); } else if ( insString.indexOf( "DEBUG |" ) >= 0 ) { StyleConstants.setForeground( sas, Color.blue ); returnVal = insString.substring( 9 ); } else if ( insString.indexOf( "INFO |" ) >= 0 ) { StyleConstants.setForeground( sas, new Color( 52, 169, 88 ) ); returnVal = insString.substring( 9 ); } else if ( insString.indexOf( "WARN |" ) >= 0 ) { StyleConstants.setForeground( sas, new Color( 230, 140, 20 ) ); returnVal = insString.substring( 9 ); } else if ( insString.indexOf( "FATAL |" ) >= 0 ) { StyleConstants.setForeground( sas, Color.red ); returnVal = insString.substring( 9 ); } else if ( insString.indexOf( "ERROR |" ) >= 0 ) { StyleConstants.setForeground( sas, Color.red ); returnVal = insString.substring( 9 ); } if ( insString.indexOf( "WARNING" ) >= 0 ) { StyleConstants.setForeground( sas, new Color( 230, 140, 20 ) ); } if ( insString.indexOf( "WrapperManager Error:" ) >= 0 || insString.indexOf( "java.lang.OutOfMemoryError:" ) >= 0 ) { StyleConstants.setForeground( sas, Color.red ); } return returnVal; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/DemoAppMainFrame.java100644 0 0 35425 12440202301 25305 0ustar 0 0 package org.tanukisoftware.wrapper.demo; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import java.util.Locale; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.UIManager; import javax.swing.WindowConstants; import javax.swing.text.html.HTMLDocument; import org.tanukisoftware.wrapper.WrapperManager; public class DemoAppMainFrame extends JFrame implements ActionListener, WindowListener { /** * Serial Version UID. */ private DemoApp m_this; private static final long serialVersionUID = -3847376282833547574L; protected JEditorPane getlogTextArea() { return m_logTextArea; } protected JEditorPane getDescTextArea() { return jEditorPane2; } JScrollPane m_logPane; protected JEditorPane m_logTextArea; JScrollPane jScrollPane2; JEditorPane jEditorPane2; JTabbedPane jTabbedPane2; DemoAppMainFrame( DemoApp m_this ) { super( DemoApp.getRes().getString( "Wrapper Demo Application" ) ); this.m_this = m_this; init(); setLocationRelativeTo( null ); // setSize( 450, 500 ); setResizable( true ); } private void init() { JMenuBar menuBar = new JMenuBar(); JMenu menu = new JMenu( "?" ); JMenuItem about = new JMenuItem( DemoApp.getRes().getString( "About.." ) ); // this.setLayout(new BorderLayout()); about.setActionCommand( "about" ); about.addActionListener( this ); addWindowListener( this ); JMenu jMenu1 = new JMenu(); jMenu1.setText( DemoApp.getRes().getString( "Test" ) ); JMenuItem jMenuItem1 = new JMenuItem(); jMenuItem1.setText( DemoApp.getRes().getString( "Start Test" ) ); jMenuItem1.setEnabled( false ); jMenuItem1.setActionCommand( "start" ); jMenuItem1.addActionListener( this ); jMenu1.add( jMenuItem1 ); JMenuItem jMenuItem2 = new JMenuItem(); jMenuItem2.setText( DemoApp.getRes().getString( "Stop Test" ) ); jMenuItem2.setActionCommand( "finish" ); jMenuItem2.addActionListener( this ); jMenu1.add( jMenuItem2 ); JMenuItem jMenuItem3 = new JMenuItem(); jMenuItem3.setAccelerator( javax.swing.KeyStroke.getKeyStroke( java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.ALT_MASK ) ); jMenuItem3.setText( DemoApp.getRes().getString( "Close" ) ); jMenuItem3.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { m_this.doAction( "finish" ); WrapperManager.stopAndReturn( 0 ); } } ); jMenu1.add( jMenuItem3 ); this.setJMenuBar( menuBar ); menu.add( about ); menuBar.add( jMenu1 ); menuBar.add( menu ); this.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); GridBagLayout gridBag1 = new GridBagLayout(); GridBagLayout gridBag2 = new GridBagLayout(); GridBagConstraints c1 = new GridBagConstraints(); GridBagConstraints c2 = new GridBagConstraints(); // this.setLayout(new FlowLayout()); // this.setLayout(layout); JPanel panel1 = new JPanel(); // panel1.setBackground( new java.awt.Color( 235, 124, 25 ) ); panel1.setLayout( gridBag1 ); JTabbedPane tabbedPane = new JTabbedPane(); // tabbedPane.setLayout(new BorderLayout()); tabbedPane.addTab( DemoApp.getRes().getString( "Failure Detections" ), panel1 ); tabbedPane.setMnemonicAt( 0, KeyEvent.VK_1 ); buildCommand( panel1, gridBag1, c1, 1, DemoApp.getRes().getString( "Crash" ), "crash", DemoApp.getRes().getString( "Simulate a Application Crash" ) ); buildCommand( panel1, gridBag1, c1, 1, DemoApp.getRes().getString( "Out of Memory" ), "out_of_mem", DemoApp.getRes().getString( "Simulate a Out Of Memory Error" ) ); buildCommand( panel1, gridBag1, c1, 1, DemoApp.getRes().getString( "Frozen" ), "frozen", DemoApp.getRes().getString( "Simulate a Frozen JVM" ) ); buildCommand( panel1, gridBag1, c1, 2, DemoApp.getRes().getString( "Deadlock" ), "deadlock", DemoApp.getRes().getString( "Simulate a Thread Deadlock" ) ); JPanel panel2 = new JPanel(); panel2.setLayout( gridBag2 ); // panel2.setBackground( Color.yellow ); tabbedPane.addTab( DemoApp.getRes().getString( "Feature Demo" ), panel2 ); tabbedPane.setMnemonicAt( 1, KeyEvent.VK_2 ); buildCommand( panel2, gridBag2, c2, 3, DemoApp.getRes().getString( "Email" ), "mail", DemoApp.getRes().getString( "Activates the email functionality" ) ); buildCommand( panel2, gridBag2, c2, 3, DemoApp.getRes().getString( "WrapperExec" ), "exec", DemoApp.getRes().getString( "Creates a managed Child Process" ) ); String os = System.getProperty( "os.name" ); if ( os.indexOf( "Windows" ) >= 0 ) { buildCommand( panel2, gridBag2, c2, 2, DemoApp.getRes().getString( "Customization" ), "customize", DemoApp.getRes().getString( "Creates a customized Binary of the wrapper" ) ); buildCommand( panel2, gridBag2, c2, 1, DemoApp.getRes().getString( "Service" ), "service", DemoApp.getRes().getString( "Installs and starts this app as Windows Service" ) ); } else { buildCommand( panel2, gridBag2, c2, 1, DemoApp.getRes().getString( "Daemon" ), "daemon", DemoApp.getRes().getString( "Installs and starts this app as Daemon" ) ); } m_logTextArea = new JEditorPane(); jEditorPane2 = new JEditorPane(); m_logTextArea.setContentType( "text/html;" ); jEditorPane2.setContentType( "text/html; charset=UTF-8" ); jEditorPane2.setEditable( false ); // Set CSS format rule Font font = UIManager.getFont( "Label.font" ); String bodyRule = "body { font-family: " + font.getFamily() + "; " + "font-size: 14pt; }"; ( ( HTMLDocument )jEditorPane2.getDocument() ).getStyleSheet().addRule( bodyRule ); m_logTextArea.setEditable( false ); //setMinimumSize( new java.awt.Dimension( 699, 300 ) ); jTabbedPane2 = new javax.swing.JTabbedPane(); m_logPane = new JScrollPane( m_logTextArea ); jScrollPane2 = new JScrollPane( jEditorPane2 ); //jTabbedPane2.setPreferredSize( new Dimension( this.getMinimumSize().width, 400 ) ); jTabbedPane2.setPreferredSize(new java.awt.Dimension(800, 400)); jTabbedPane2.addTab( DemoApp.getRes().getString( "Description" ), jScrollPane2 ); jTabbedPane2.addTab( DemoApp.getRes().getString( "Wrapper Output" ), m_logPane ); getContentPane().setLayout( new BorderLayout() ); getContentPane().add( tabbedPane, java.awt.BorderLayout.PAGE_START ); getContentPane().add( jTabbedPane2, java.awt.BorderLayout.CENTER ); this.setVisible( true ); this.pack(); tabbedPane.setMaximumSize( new Dimension( tabbedPane.getMaximumSize().width, tabbedPane.getSize().height ) ); } private void buildCommand( JComponent container, GridBagLayout gridBag, GridBagConstraints c, int level, String label, String command, Object description ) { JButton button = new JButton( label ); button.setActionCommand( command ); c.fill = GridBagConstraints.BOTH; c.gridwidth = 1; c.gridx = 0; c.insets = new Insets( 10, 10, 10, 10 ); gridBag.setConstraints( button, c ); container.add( button ); button.addActionListener( this ); // button.addMouseListener( this ); // Timer t = new Timer(10, this); JButton buttonhelp = new JButton( "?" ); buttonhelp.setActionCommand( "help" + command ); c.fill = GridBagConstraints.NONE; c.gridwidth = 1; c.gridx = 1; c.insets = new Insets( 10, 10, 10, 10 ); gridBag.setConstraints( buttonhelp, c ); container.add( buttonhelp ); buttonhelp.addActionListener( this ); c.fill = GridBagConstraints.NONE; c.gridwidth = GridBagConstraints.REMAINDER; JComponent desc; if ( description instanceof String ) { desc = new JLabel( ( String )description ); } else if ( description instanceof JComponent ) { desc = ( JComponent )description; } else { desc = new JLabel( description.toString() ); } c.gridx = 2; c.insets = new Insets( 10, 10, 10, 10 ); gridBag.setConstraints( desc, c ); container.add( desc ); if ( level == 2 ) { if ( !WrapperManager.isStandardEdition() ) { button.setEnabled( false ); button.setToolTipText( DemoApp.getRes().getString( "Requires the Standard Edition." ) ); } } else if ( level == 3 ) { if ( !WrapperManager.isProfessionalEdition() ) { button.setEnabled( false ); button.setToolTipText( DemoApp.getRes().getString( "Requires the Professional Edition." ) ); } } } String getHTMLDescription( String action ) { try { String rsname = "html/" + action + "_" + Locale.getDefault().getLanguage() + ".html"; // System.out.println( Locale.getDefault().getLanguage() + // " trying ot open " +rsname); URL url = this.getClass().getResource( rsname ); Reader br; try { br = new BufferedReader( new InputStreamReader( url.openStream(), "utf8" ) ); } catch ( NullPointerException npe1 ) { try { // String test = this.getClass().getResource( "html/" + // action + "_en.html" ).getFile(); br = new BufferedReader( new InputStreamReader( this.getClass().getResource( "html/" + action + "_en.html" ).openStream(), "utf8" ) ); } catch ( NullPointerException npe2 ) { return "" + DemoApp.getRes().getString( "No description for {0} found...", action ) + ""; } } char[] buffer = new char[ 4096 ]; String t = ""; while ( br.read( buffer ) != -1 ) { t = t.concat( new String( buffer ) ); } br.close(); return t; } catch ( IOException e ) { e.printStackTrace(); } return "" + DemoApp.getRes().getString( "No description for {0} found...", action ) + ""; } /************************************************************************** * ActionListener Methods *************************************************************************/ public void actionPerformed( ActionEvent event ) { String action = event.getActionCommand(); if ( !action.startsWith( "help" ) ) { if ( action.equals( "start" ) ) { this.getJMenuBar().getMenu( 0 ).getItem( 0 ).setEnabled( false ); this.getJMenuBar().getMenu( 0 ).getItem( 1 ).setEnabled( true ); m_this.doAction( action ); } else if ( action.equals( "finish" ) ) { this.getJMenuBar().getMenu( 0 ).getItem( 0 ).setEnabled( true ); this.getJMenuBar().getMenu( 0 ).getItem( 1 ).setEnabled( false ); m_this.doAction( action ); } else if ( action.equals( "about" ) ) { // Create the mask. createAboutScreen(); } else if ( action.equals( "daemon" ) ) { jEditorPane2.setText( getHTMLDescription( action ) ); jEditorPane2.setCaretPosition( 0 ); // Create the mask. this.jTabbedPane2.setSelectedIndex( 1 ); m_this.doAction( action ); } else { jEditorPane2.setText( getHTMLDescription( action ) ); jEditorPane2.setCaretPosition( 0 ); this.jTabbedPane2.setSelectedIndex( 1 ); m_this.doAction( action ); } } else { jEditorPane2.setText( getHTMLDescription( action.substring( 4 ) ) ); // System.out.println(getHTMLDescription( action.substring( 4 ) )); jEditorPane2.setCaretPosition( 0 ); this.jTabbedPane2.setSelectedIndex( 0 ); } } private void createAboutScreen() { new AboutDialog( this ).setVisible( true ); } /************************************************************************** * WindowListener Methods *************************************************************************/ public void windowOpened( WindowEvent e ) { } public void windowClosing( WindowEvent e ) { if ( !m_this.isTestCaseRunning() || JOptionPane.showConfirmDialog( this, DemoApp.getRes().getString( "A test case is still running.\nDo you really want to exit and stop this one??" ) ) == JOptionPane.YES_OPTION ) { System.out.println( DemoApp.getRes().getString( "Stopping..." ) ); m_this.doAction( "finish" ); WrapperManager.stopAndReturn( 0 ); } } public void windowClosed( WindowEvent e ) { } public void windowIconified( WindowEvent e ) { } public void windowDeiconified( WindowEvent e ) { } public void windowActivated( WindowEvent e ) { } public void windowDeactivated( WindowEvent e ) { } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/ExtensionFilter.java100644 0 0 3605 12440202301 25275 0ustar 0 0 package org.tanukisoftware.wrapper.demo; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.File; import javax.swing.filechooser.FileFilter; class ExtensionFilter extends FileFilter { String description; String extensions[]; public ExtensionFilter( String description, String extension ) { this( description, new String[] { extension } ); } public ExtensionFilter( String description, String extensions[] ) { if ( description == null ) { this.description = extensions[0]; } else { this.description = description; } this.extensions = ( String[] )extensions.clone(); toLower( this.extensions ); } private void toLower( String array[] ) { for ( int i = 0, n = array.length; i < n; i++ ) { array[i] = array[i].toLowerCase(); } } public String getDescription() { return description; } public boolean accept( File file ) { if ( file.isDirectory() ) { return true; } else { String path = file.getAbsolutePath().toLowerCase(); for ( int i = 0, n = extensions.length; i < n; i++ ) { String extension = extensions[i]; if ( ( path.endsWith( extension ) && ( path.charAt( path.length() - extension.toLowerCase().length() - 1 ) ) == '.' ) ) { return true; } } } return false; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/MailDialog.java100644 0 0 41577 12440202301 24207 0ustar 0 0 package org.tanukisoftware.wrapper.demo; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.awt.GridBagConstraints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import org.tanukisoftware.wrapper.WrapperManager; public class MailDialog extends JDialog { /** * */ private static final long serialVersionUID = -5989594238193947229L; private JPanel jPanel1, jPanel2, jPanel3, jPanel4; private JCheckBox jCheckBox1, jCheckBox2, jCheckBox3, jCheckBox4, jCheckBox5, jCheckBox6, jCheckBox7, jCheckBox8, jCheckBox9, jCheckBox10, jCheckBox11, jCheckBox12, jCheckBox13, jCheckBox14; private JTextField jTextField1, jTextField2, jTextField3, jTextField4; private JLabel jLabel1, jLabel2, jLabel3, jLabel4; private JButton jButton1, jButton2; private GridBagConstraints gridBagConstraints; private int result; private int m_port; private String m_recipient, m_sender, m_server, m_events; public String getEvents() { return this.m_events; } public String getRecipients() { return this.m_recipient; } public String getSender() { return this.m_sender; } public String getServer() { return this.m_server; } public int getPort() { return this.m_port; } public int getResult() { return this.result; } public MailDialog() { jPanel1 = new javax.swing.JPanel(); jPanel2 = new javax.swing.JPanel(); jCheckBox1 = new javax.swing.JCheckBox(); jCheckBox2 = new javax.swing.JCheckBox(); jCheckBox3 = new javax.swing.JCheckBox(); jCheckBox4 = new javax.swing.JCheckBox(); jCheckBox5 = new javax.swing.JCheckBox(); jCheckBox6 = new javax.swing.JCheckBox(); jCheckBox7 = new javax.swing.JCheckBox(); jCheckBox8 = new javax.swing.JCheckBox(); jPanel3 = new javax.swing.JPanel(); jTextField1 = new javax.swing.JTextField(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); jTextField2 = new javax.swing.JTextField(); jLabel3 = new javax.swing.JLabel(); jTextField3 = new javax.swing.JTextField(); jLabel4 = new javax.swing.JLabel(); jTextField4 = new javax.swing.JTextField(); jPanel4 = new javax.swing.JPanel(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); this.m_events = ""; this.getContentPane().setLayout( new java.awt.GridBagLayout() ); this.setTitle( DemoApp.getRes().getString( "Wrapper DemoApp: Event Mails" ) ); jPanel1.setLayout( new java.awt.GridBagLayout() ); jPanel2.setBorder( javax.swing.BorderFactory.createTitledBorder( DemoApp.getRes().getString( "EventTypes" ) ) ); jPanel2.setAlignmentX( 0.0F ); jPanel2.setAlignmentY( 0.0F ); jPanel2.setMinimumSize( new java.awt.Dimension( 350, 61 ) ); jPanel2.setLayout( new java.awt.GridBagLayout() ); jCheckBox1.setText( "wrapper_start" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox1, gridBagConstraints ); jCheckBox2.setText( "jvm_prelaunch" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox2, gridBagConstraints ); jCheckBox3.setText( "jvm_start" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox3, gridBagConstraints ); jCheckBox4.setText( "jvm_started" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox4, gridBagConstraints ); jCheckBox5.setText( "jvm_stop" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox5, gridBagConstraints ); jCheckBox6.setText( "jvm_stopped" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox6, gridBagConstraints ); jCheckBox7.setText( "wrapper_stop" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox7, gridBagConstraints ); jCheckBox14 = new JCheckBox(); jCheckBox14.setText( "jvm_restart" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox14, gridBagConstraints ); jCheckBox9 = new JCheckBox(); jCheckBox9.setText( "jvm_failed_invocation" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox9, gridBagConstraints ); jCheckBox10 = new JCheckBox(); jCheckBox10.setText( "jvm_max_failed_invocations" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox10, gridBagConstraints ); jCheckBox11 = new JCheckBox(); jCheckBox11.setText( "jvm_kill" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox11, gridBagConstraints ); jCheckBox12 = new JCheckBox(); jCheckBox12.setText( "jvm_killed" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox12, gridBagConstraints ); jCheckBox13 = new JCheckBox(); jCheckBox13.setText( "jvm_unexpected_exit" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; jPanel2.add( jCheckBox13, gridBagConstraints ); jPanel1.add( jPanel2, new java.awt.GridBagConstraints() ); jPanel3.setBorder( javax.swing.BorderFactory.createTitledBorder( DemoApp.getRes().getString( "Mail Setup" ) ) ); jPanel3.setLayout( new java.awt.GridBagLayout() ); jTextField1.setColumns( 20 ); jTextField1.setText( WrapperManager.getProperties().getProperty( "wrapper.event.default.email.sender" ) ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; jPanel3.add( jTextField1, gridBagConstraints ); jLabel1.setText( DemoApp.getRes().getString( "Sender:" ) ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; jPanel3.add( jLabel1, gridBagConstraints ); jCheckBox8.setText( DemoApp.getRes().getString( "Attach Logfile" ) ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; jPanel3.add( jCheckBox8, gridBagConstraints ); jLabel2.setText( DemoApp.getRes().getString( "Recipient:" ) ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; jPanel3.add( jLabel2, gridBagConstraints ); jTextField2.setColumns( 30 ); jTextField2.setText( WrapperManager.getProperties().getProperty( "wrapper.event.default.email.recipient" ) ); jTextField2.setToolTipText( DemoApp.getRes().getString( "Please separate mulitple recipients with a semicolon '';''" ) ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; jPanel3.add( jTextField2, gridBagConstraints ); jLabel3.setText( "Mail Server:" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; jPanel3.add( jLabel3, gridBagConstraints ); jTextField3.setColumns( 15 ); jTextField3.setText( WrapperManager.getProperties().getProperty( "wrapper.event.default.email.smtp.host" ) ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; jPanel3.add( jTextField3, gridBagConstraints ); jLabel4.setText( "Port:" ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; jPanel3.add( jLabel4, gridBagConstraints ); jTextField4.setColumns( 3 ); String port = WrapperManager.getProperties().getProperty( "wrapper.event.default.email.smtp.port" ); jTextField4.setText( port == null ? "25" : port ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 2; jPanel3.add( jTextField4, gridBagConstraints ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; jPanel1.add( jPanel3, gridBagConstraints ); jButton1.setText( DemoApp.getRes().getString( "OK" ) ); jButton1.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { if ( jCheckBox1.isSelected() || jCheckBox2.isSelected() || jCheckBox3.isSelected() || jCheckBox4.isSelected() || jCheckBox5.isSelected() || jCheckBox6.isSelected() || jCheckBox7.isSelected() || jCheckBox9.isSelected() || jCheckBox10.isSelected() || jCheckBox11.isSelected() || jCheckBox12.isSelected() || jCheckBox13.isSelected() || jCheckBox14.isSelected() ) { if ( jTextField1.getText().length() == 0 || jTextField2.getText().length() == 0 || jTextField3.getText().length() == 0 || jTextField4.getText().length() == 0 ) { JOptionPane.showMessageDialog( MailDialog.this, DemoApp.getRes().getString( "All text fields need to be filled out!" ), DemoApp.getRes().getString( "Input missing!" ), JOptionPane.OK_OPTION ); } else { if ( jCheckBox1.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox1.getText() + ".email=TRUE " ); } if ( jCheckBox2.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox2.getText() + ".email=TRUE " ); } if ( jCheckBox3.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox3.getText() + ".email=TRUE " ); } if ( jCheckBox4.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox4.getText() + ".email=TRUE " ); } if ( jCheckBox5.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox5.getText() + ".email=TRUE " ); } if ( jCheckBox6.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox6.getText() + ".email=TRUE " ); } if ( jCheckBox7.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox7.getText() + ".email=TRUE " ); } if ( jCheckBox9.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox9.getText() + ".email=TRUE " ); } if ( jCheckBox10.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox10.getText() + ".email=TRUE " ); } if ( jCheckBox11.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox11.getText() + ".email=TRUE " ); } if ( jCheckBox12.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox12.getText() + ".email=TRUE " ); } if ( jCheckBox13.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox13.getText() + ".email=TRUE " ); } if ( jCheckBox14.isSelected() ) { m_events = m_events.concat( "wrapper.event." + jCheckBox14.getText() + ".email=TRUE " ); } if ( jCheckBox8.isSelected() ) { m_events = m_events.concat( "wrapper.event.default.email.attach_log=TRUE" ); } m_recipient = jTextField2.getText(); m_sender = jTextField1.getText(); m_server = jTextField3.getText(); m_port = Integer.parseInt( jTextField4.getText() ); result = 1; MailDialog.this.setVisible( false ); } } else { JOptionPane.showMessageDialog( MailDialog.this, DemoApp.getRes().getString( "Please select at least one event!" ), DemoApp.getRes().getString( "Input missing!" ), JOptionPane.OK_OPTION ); } } } ); jPanel4.add( jButton1 ); jButton2.setText( DemoApp.getRes().getString( "Cancel" ) ); jButton2.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent e ) { result = 0; MailDialog.this.dispose(); } } ); jPanel4.add( jButton2 ); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; jPanel1.add( jPanel4, gridBagConstraints ); this.getContentPane().add( jPanel1, new java.awt.GridBagConstraints() ); this.setLocation( this.getParent().getLocation() ); this.setResizable( false ); this.setModal( true ); this.pack(); // this.setVisible(true); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/crash_en.html100644 0 0 3535 12440202301 24726 0ustar 0 0

Crash

The Wrapper includes a lightweight native library which is used to handle system events. The library also contains a native method, which is used for testing, to cause an access violation in native code due to a NULL reference.

Depending on the JVM, this will give different output. In the example below, the JVM created a core dump which takes about a minute to save. During this time, the JVM appears to be hung so the Wrapper kills and restarts it.

Console Output:
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
jvm 1    | WARNING: Attempting to cause an access violation...
jvm 1    | #
jvm 1    | # An EXCEPTION_ACCESS_VIOLATION exception has been detected in native code outside the VM.
jvm 1    | # Program counter=0x8f7105f
jvm 1    | #
wrapper  | JVM is hung: Timed out waiting for signal from JVM.
wrapper  | Java Virtual Machine did not exit on request, terminated
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/crash_ja.html100644 0 0 4256 12440202301 24717 0ustar 0 0

Crash

Wrapperは、軽量なネイ?ィブ?ライブラリーを含んでおり? シス??・イベントを取り扱?ときに利用されます?? ライブラリーには、ネイ?ィブ?メソ?ドも含んでおり? ?スト用に利用され? NULL 参?によるネイ?ィブ?コードでアクセス違反を引き起こします??

JVM次第ですが、これ?異なる?力結果となります?? こ?下記?例では、保存に???かかりますが、コア・?ンプを作?します?? そ??要時間にもよりますが? JVMがハングア?プして?るよ?に見える可能性もあり?? そ?場合?Wrapperがハングア?プと検知して強制終?して再起動させる可能性もあります??

コンソール出?:
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
jvm 1    | WARNING: Attempting to cause an access violation...
jvm 1    | #
jvm 1    | # An EXCEPTION_ACCESS_VIOLATION exception has been detected in native code outside the VM.
jvm 1    | # Program counter=0x8f7105f
jvm 1    | #
wrapper  | JVM is hung: Timed out waiting for signal from JVM.
wrapper  | Java Virtual Machine did not exit on request, terminated
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/customize_en.html100644 0 0 24015 12440202301 25664 0ustar 0 0

Customize your Wrapper

With the release of Wrapper version 3.3.7, the Wrapper provides the ability to change some of its resources and to customize its appearance on Windows.

When customizing the Wrapper binary "wrapperw.exe", a new version of the binary will be created with the new resources specified with the "--customize" command. The resulting binary will be locked, meaning that it is no longer possible to customize it.

When creating a new customer binary, any of the following arguments can be combined. The "--target {target.exe}" argument is always required.

Please note that the paths of all file names are relative to the location of the Wrapper binary, not necessarily relative to the location of the caller. For example, the following command will create the target file in the same directory as the wrapperw.exe binary and expect to find the new icon and splashscreen in that directory as well:

bin\wrapperw.exe --customize --target myapp.exe --icon myicon.ico --splash mysplash.bmp

The Target Executable

When the Wrapper binary is customized, it is necessary to always specify a new file name for the customized version. The Wrapper will always overwrite the file if it already exists.

wrapperw.exe --target myapp.exe

Putting the parameter all together would result to a command line like this:

bin\wrapperw.exe --customize --icon MyIcon.ico --splash MySplash.bmp --target MyApp.exe

This command will create a new executable MyApp.exe in the same directory the wrapperw.exe is located, with a customized Icon and Splash Screen.

Customize The Icon

NOTE

This function requires either Standard or Professional Edition of the Java Service Wrapper.

The Wrapper is shipped with a default icon, however the Wrapper has proven to be also an excellent Application launcher, for this purpose a software developer may wish to replace the Icon with that of the product the Wrapper is being used with.

The icon file is a standard multi layer icon file that contains all of the resolution and icon sizes that need to be supported.

Example:
wrapperw.exe --target myapp.exe --icon myicon.ico

Customize The Splash Screen

NOTE

This function requires either Standard or Professional Edition of the Java Service Wrapper.

The consoleless version of the Wrapper, wrapperw.exe, will by default show a Splash Screen on startup. This splash screen can be customized with an image representing the product that the Wrapper is being used with.

Having the Wrapper display a splash screen rather than doing so from within Java has the benefit of making the applications startup seem very responsive because the splash screen will be displayed before the JVM is launched and can remain visible as the Java application's classes are loaded and initialized.

The way the splash screen behaves can be controled with the wrapper.splashscreen.mode property.

This argument is illegal for the wrapper.exe binary because it does not display a splash screen.

Example:
wrapperw.exe --target myapp.exe --splash mysplash.bmp

Currently only bitmap (*.bmp) files are supported. There are no size or bit-depth restrictions set.

wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/customize_ja.html100644 0 0 26047 12440202301 25663 0ustar 0 0

自?のWrapperをカスタマイズする

Wrapperバ?ジョン3.3.7のリリースで? Wrapperは、リソースの?くつかを変更したり?? Windows上で外観をカスタマイズしたり?などの能力?備えた機?の提供を開始しました?

Wrapperバイナリ版?wrapperw.exe」をカスタマイズするとき?? "--customize"コマンドで?定された新しいリソースで新しいバ?ジョンのバイナリが作?されます?? そ?結果となるバイナリはロ?クされ、もは?カスタマイズはできなくなります??

新しいカスタマ?・バイナリを作?するとき?次の引数を結合できます?? 引数 "--target {target.exe}" は、常に?要です??

全てのファイル名?パスが?呼び出し??への相対?な配置場?である?要?なく?? Wrapperバイナリの配置場?への相対であることに注意してください? 例えば、次のコマンドでは、??wrapperw.exe」バイナリと 同じ?ィレクトリーにターゲ?ト?ファイルを作?し、同様に、その?ィレクトリーに新しいアイコン? スプラ?シュ・スクリーンを探すことになります?

bin\wrapperw.exe --customize --target myapp.exe --icon myicon.ico --splash mysplash.bmp

実行ターゲ?ト?

Wrapperバイナリがカスタマイズされるとき?? 常に、カスタマイズ・バ?ジョン用に、新しい ファイル名を?定する?要があります?? 既に同じファイル名が存在する場合には、Wrapperは常にそ?ファイルを上書きします??

wrapperw.exe --target myapp.exe

全てまとめてパラメーターを置くと、このような コマンドラインとなります?

bin\wrapperw.exe --customize --icon MyIcon.ico --splash MySplash.bmp --target MyApp.exe

こ?コマンド?? ?wrapperw.exe」が配置して?ある同じ?ィレクトリーに? カスタマイズされたアイコン?スプラ?シュ・スクリーンと共に? 新しい実行ファイル?MyApp.exe」を作?します??

アイコンをカスタマイズする

NOTE

こ?機?を利用するためには? Java Service Wrapperのスタン?ード版、あるいは、?ロフェ?ショナル?をご利用ください?

Wrapperは、デフォルト?アイコンを同梱して配?されて?ますが? しかしながら、Wrapperを同梱して?る商品?アイコンで置き換えた?と??開発?の希望のために? Wrapperは、?晴らし?アプリケーション・ランチャーでもあると??役目も提供して?ます??

アイコン・ファイルは、標準?マルチ?レイヤー・アイコン・ファイルであり? サポ?トされる?要がある全ての解像度?アイコン・サイズを含んで?ます??

設定例?
wrapperw.exe --target myapp.exe --icon myicon.ico

スプラ?シュ・スクリーンをカスタマイズする

NOTE

こ?機?を利用するためには? Java Service Wrapperのスタン?ード版、あるいは、?ロフェ?ショナル?をご利用ください?

Wrapperのコンソールレス版??wrapperw.exe」?? ?フォルトで、スタート時にスプラ?シュ・スクリーンを表示します?? こ?スプラ?シュ・スクリーンは、Wrapperを同梱して?る商品?合わせたイメージ画像で置き換えることでカスタマイズすることができま

Java?部からではなく?Wrapperにスプラ?シュ・スクリーンを表示させることは? アプリケーション・スタートア?プをとてもresponsiveらしくさせる利点があります?? そ??由は、スプラ?シュ・スクリーンはJVM起動前に表示され? Javaアプリケーションのクラスがロード(読み込み?されて初期化されて見える状態を維持して?るためです??

?wrapper.splashscreen.mode? プロパティを使って、スプラ?シュ・スクリーンの動作につ?てコントロールすることができます??

こ?引数では、スプラ?シュ・スクリーンを表示しな?ため? ?wrapper.exe」バイナリでは非合法です??

Example:
wrapperw.exe --target myapp.exe --splash mysplash.bmp

現在のところ、唯?、ビ?ト?ッ? (*.bmp) ファイルをサポ?トして?ます?? 画像サイズ?ビット深さ?制限?ありません?

wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/daemon_en.html100644 0 0 5115 12440202301 25065 0ustar 0 0

Installing The Application To Start on Reboot

Introduced in version 3.4.0, the script provides a way to embed the wrapper (and finally your application).
The script will automatically detect your OS - on Linux plattforms also some distributions - and perform the steps necessary to install the wrapper script into the initialization process of your OS.

$ sudo bin/testwrapper install
[sudo] password for tanuki:
Detected Ubuntu:
Installing service testwrapper from current directory /home/tanuki/wrapper/bin
Adding system startup for /etc/init.d/testwrapper ...
...

As the script installs itself into your OS, it is necessary to run the install (and uninstall) option as user root!

For freebsd and MacOSX users the script provides a default configuration file how launchd or initd will handle the script during the boot process. However it is possible to customize this step.

If you wish to uninstall/remove the wrapper from the system initialization run the script (as root!) passing the action parameter "remove". This will first stop the running wrapper application and finally clean itself from initialization.

$ sudo bin/testwrapper remove
[sudo] password for tanuki:
Stopping Test Wrapper Sample Application...
Stopped Test Wrapper Sample Application.
Detected Ubuntu:
Removing service testwrapper from current directory /home/tanuki/wrapper/bin
...
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/daemon_ja.html100644 0 0 5214 12440202301 25055 0ustar 0 0

リブ?ト(?起動)でスタートするよ?にアプリケーションをインスト?ルする

Introduced in version 3.4.0, the script provides a way to embed the wrapper (and finally your application).
The script will automatically detect your OS - on Linux plattforms also some distributions - and perform the steps necessary to install the wrapper script into the initialization process of your OS.

$ sudo bin/testwrapper install
[sudo] password for tanuki:
Detected Ubuntu:
Installing service testwrapper from current directory /home/tanuki/wrapper/bin
Adding system startup for /etc/init.d/testwrapper ...
...

As the script installs itself into your OS, it is necessary to run the install (and uninstall) option as user root!

For freebsd and MacOSX users the script provides a default configuration file how launchd or initd will handle the script during the boot process. However it is possible to customize this step.

If you wish to uninstall/remove the wrapper from the system initialization run the script (as root!) passing the action parameter "remove". This will first stop the running wrapper application and finally clean itself from initialization.

$ sudo bin/testwrapper remove
[sudo] password for tanuki:
Stopping Test Wrapper Sample Application...
Stopped Test Wrapper Sample Application.
Detected Ubuntu:
Removing service testwrapper from current directory /home/tanuki/wrapper/bin
...
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/deadlock_en.html100644 0 0 33552 12440202301 25416 0ustar 0 0

wrapper.check.deadlock

This property, in combination with the other properties,

are used to configure how the Wrapper monitors a JVM for deadlocked threads. This can be very useful to detect and then work around potentially fatal problems which would otherwise be difficult if not impossible to work around.

Thread deadlock checks require that at least Java version 1.5 is used. Only JVMs will ignore the checks.

Checking for Deadlocks is fairly quick, but it does involve briefly locking and taking a snapshot of all threads so this property is FALSE by default.

Example: (Deadlock Check: Off)
wrapper.check.deadlock=FALSE

Simple Example:

Please read over the property details below, but the following simple example will configure the Wrapper to log the location of a deadlock and then immediately restart the JVM.

Example:
wrapper.check.deadlock=TRUE
wrapper.check.deadlock.interval=60
wrapper.check.deadlock.action=RESTART
wrapper.check.deadlock.output=FULL

Deadlock?:

Deadlocks can occur when two or more threads are locking resources in an order which results in all threads waiting indefinitely.

The simplest example is where Thread A locks Object A and then attempts to lock Object B, while another Thread B has Object B locked and is waiting to lock Object A. In this case, Thread A will never release Object A because it is waiting for Object B. This will never happen because Thread B will keep Object B locked indefinitely as it waits for Object A to become available.

wrapper.check.deadlock.interval

The wrapper.check.deadlock.interval property makes it possible to control the interval at which the Wrapper looks for deadlocks in an application. It can be set to any interval starting with once per second, but it defaults to "60" (once per minute). In general, for applications which are known to be stable, it may be fine to greatly decrease the frequency of these deadlock checks.

Example: (every 60 seconds)
wrapper.check.deadlock.interval=60

wrapper.check.deadlock.action

The wrapper.check.deadlock.action property makes it possible to control what the Wrapper does when a deadlock is detected. The default action is to RESTART.

Example:
wrapper.check.deadlock.action=RESTART

Possible actions are:

  • RESTART -

    will stop the current JVM and then restart a new invocation.

  • SHUTDOWN -

    will stop the JVM as well as the Wrapper.

  • DUMP -

    will invoke a thread dump. Note that because deadlocks are by definition permanent, the deadlocked state will persist until the JVM has been restarted, meaning that the thread dump will also be invoked at each interval.

  • USER_<n> -

    will cause a user defined event to be fired in the Professional Edition.

  • NONE -

    is useful because it will prevent any triggers with a higher number from being triggered.

It is possible to specify more than one actions by separating then with a space or comma. When more than one action is specified, they will be executed in rapid succession in the order specified.

The following example will perform a thread dump and then restart the JVM.

Example:
wrapper.check.deadlock.action=DUMP,RESTART

wrapper.check.deadlock.output

The wrapper.check.deadlock.output property makes it possible to control what information the Wrapper causes to be logged when a deadlock is detected. The default output level is FULL.

Example:
wrapper.check.deadlock.output=FULL

Possible output levels are:

  • FULL -

    will cause the WrapperManager class within the JVM to output a report which includes full stack traces for the threads involved in the deadlock.

    Output Example of "FULL":
    INFO   | jvm 1    | WrapperManager Error: Found 2 deadlocked threads!
    INFO   | jvm 1    | WrapperManager Error: =============================
    INFO   | jvm 1    | WrapperManager Error: "Locker-2" tid=18
    INFO   | jvm 1    | WrapperManager Error:   java.lang.Thread.State: BLOCKED
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.lockSecond(DeadLock.java:64)
    INFO   | jvm 1    | WrapperManager Error:       - waiting on <0x000000002fcac6db> (a java.lang.Object) owned by "Locker-1" tid=17
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.lockFirst(DeadLock.java:83)
    INFO   | jvm 1    | WrapperManager Error:       - locked <0x0000000029c56c60> (a java.lang.Object)
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.access$100(DeadLock.java:22)
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock$1.run(DeadLock.java:42)
    INFO   | jvm 1    | WrapperManager Error:
    INFO   | jvm 1    | WrapperManager Error: "Locker-1" tid=17
    INFO   | jvm 1    | WrapperManager Error:   java.lang.Thread.State: BLOCKED
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.lockSecond(DeadLock.java:64)
    INFO   | jvm 1    | WrapperManager Error:       - waiting on <0x0000000029c56c60> (a java.lang.Object) owned by "Locker-2" tid=18
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.lockFirst(DeadLock.java:83)
    INFO   | jvm 1    | WrapperManager Error:       - locked <0x000000002fcac6db> (a java.lang.Object)
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.access$100(DeadLock.java:22)
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock$1.run(DeadLock.java:42)
    INFO   | jvm 1    | WrapperManager Error:
    INFO   | jvm 1    | WrapperManager Error: =============================
    STATUS | wrapper  | A Thread Deadlock was detected in the JVM.  Restarting JVM.
  • SIMPLE -

    will cause the WrapperManager class within the JVM to output a report which includes only a brief summary naming the threads and objects involved in the deadlock. In many cases, this is enough especially for known problems.

    Output Example of "SIMPLE":
    INFO   | jvm 1    | WrapperManager Error: Found 2 deadlocked threads!
    INFO   | jvm 1    | WrapperManager Error: =============================
    INFO   | jvm 1    | WrapperManager Error: "Locker-2" BLOCKED waiting on a java.lang.Object owned by "Locker-1"
    INFO   | jvm 1    | WrapperManager Error: "Locker-1" BLOCKED waiting on a java.lang.Object owned by "Locker-2"
    INFO   | jvm 1    | WrapperManager Error: =============================
    STATUS | wrapper  | A Thread Deadlock was detected in the JVM.  Restarting JVM.
  • NONE -

    will cause the WrapperManager class within the JVM to suppress all output. This may be desired for production systems when a problem is known but you don't want or need to maintain too much information in the logs. The Wrapper process, as in the other options, will always log a single entry to provide a reason why the triggered action takes place.

    Output Example of "NONE":
    STATUS | wrapper  | A Thread Deadlock was detected in the JVM.  Restarting JVM.

wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/deadlock_ja.html100644 0 0 36542 12440202301 25410 0ustar 0 0

コンフィギュレーション・プロパティの概?

wrapper.check.deadlock プロパティ

こ?プロパティは、他?プロパティとの?み合わせで?

??ドロ?クしたスレ?ドにつ?て JVMをどのようにモニター?監視)するかを設定するために使われます?? これは、何とか回避策がある場合には? 難しいような潜在?な致命?な問題を検知して回避するのに、とても役に立ちます??

スレ?ド???ドロ?ク・チェ?クは、少なくと?Javaバ?ジョン1.5の利用して?ることが?要です?? JVM?け?チェ?クを無視します??

??ドロ?クのチェ?クの処?は、わりと高?ですが? 全てのスレ?ドを?時的にロ?クしてスナップショ?トをとります?で? こ?プロパティは?フォルトで「FALSE」になって?ます??

設定例:(デ?ドロ?ク・チェ?ク?OFF??
wrapper.check.deadlock=FALSE

設定例?

プロパティの詳細につ?て下記をご覧?ただきますが? 次のシンプルな例では、デ?ドロ?クの場?をログ化するよ?にWrapperを設定してあり? 即座にJVMを?起動します??

設定例?
wrapper.check.deadlock=TRUE
wrapper.check.deadlock.interval=60
wrapper.check.deadlock.action=RESTART
wrapper.check.deadlock.output=FULL

??ドロ?クって??

?数のスレ?ドがリソースをロ?クして?るときに? 全てのスレ?ドが無制限に?ち状態になる状態になり?? ??ドロ?クが起きることがあります??

?番シンプルな例だと、スレ?ドAがオブジェクトAをロ?クして?る状態で? オブジェクトBのロ?クを試みるケースのときに? そ?間?他?スレ?ドBがオブジェクトBをロ?クした状態で オブジェクトAをロ?クしよ?と?機して?るケースです?? こ?ケースでは? スレ?ドAは、オブジェクトB?ちのため? オブジェクトAを決して開放されることはありません? 同時に、スレ?ドBは、オブジェクトAが有効になる?を?って?るため?? オブジェクトBを永?にロ?クしたままになるため?? 両?とも決して前に進めるはずがありません?

wrapper.check.deadlock.interval

?wrapper.check.deadlock.interval? プロパティでは? Wrapperがアプリケーションの??ドロ?クを探? インターバル??定間隔?周期)?コントロールを可能にします?? ?短で?秒毎に?回のインターバルを設定できますが? ?フォルトでは?60」(1??あたり1回?です?? ?般?に、状態が安定して?ると?かって?るアプリケーションの場合には? こ???ドロ?ク・チェ?クの頻度を大?に下げることも良?でしょ??

設定例:(60秒毎?
wrapper.check.deadlock.interval=60

wrapper.check.deadlock.action

?wrapper.check.deadlock.action? プロパティでは? ??ドロ?クを検知したとき?Wrapperはど?するか?? Wrapperの動作につ?てのコントロールを可能にします?? ?フォルト?動作では、??RESTART」です??

設定例:(?起動する?
wrapper.check.deadlock.action=RESTART

可能な動作?次のとおり??

  • RESTART -

    カレン?JVMを停止して、新しい「起動?試み??invocation???再起動します??

  • SHUTDOWN -

    JVMを停止して、同様にWrapperも停止します??

  • DUMP -

    スレ?ド??ンプを呼び出します?? 当然のことながら、デ?ドロ?クが永続して?るため?? JVMが?起動するまでずっと、デ?ドロ?クしたス?ート(状態)が持続します?? つまり?スレ?ド??ンプもまた各インターバル??定間隔?周期)ごとに呼び出されま? のでご注意く?さい?

  • DUMP_RESTART -

    スレ?ド??ンプを呼び出し?? カレン?JVMを停止して、新しい「起動?試み??invocation???再起動します??

  • DUMP_SHUTDOWN -

    スレ?ド??ンプを呼び出し?? JVMを停止して、同様にWrapperも停止します??

  • NONE -

    これは便利です?? なぜなら??高い数値を持つトリガーなら?? ?かなるトリガーもトリガーされることを避けることができるので? because it will prevent any triggers with a higher number from being triggered.

wrapper.check.deadlock.output

?wrapper.check.deadlock.output? プロパティでは? ??ドロ?クを検知したとき?Wrapperがログ化する情報をコントロールを可能にします?? ?フォルト?力では、??FULL」です??

設定例:(完?なフルログ??
wrapper.check.deadlock.output=FULL

可能な出力レベルは次のとおり??

  • FULL -

    JVM?部でWrapperManagerクラスが?? ??ドロ?クで呼び出されたスレ?ド?完?なスタ?ク・トレース??時記?の軌跡?を含? レポ?トを出力します??

    「FULL?フル???出力例?
    INFO   | jvm 1    | WrapperManager Error: Found 2 deadlocked threads!
    INFO   | jvm 1    | WrapperManager Error: =============================
    INFO   | jvm 1    | WrapperManager Error: "Locker-2" tid=18
    INFO   | jvm 1    | WrapperManager Error:   java.lang.Thread.State: BLOCKED
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.lockSecond(DeadLock.java:64)
    INFO   | jvm 1    | WrapperManager Error:       - waiting on <0x000000002fcac6db> (a java.lang.Object) owned by "Locker-1" tid=17
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.lockFirst(DeadLock.java:83)
    INFO   | jvm 1    | WrapperManager Error:       - locked <0x0000000029c56c60> (a java.lang.Object)
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.access$100(DeadLock.java:22)
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock$1.run(DeadLock.java:42)
    INFO   | jvm 1    | WrapperManager Error:
    INFO   | jvm 1    | WrapperManager Error: "Locker-1" tid=17
    INFO   | jvm 1    | WrapperManager Error:   java.lang.Thread.State: BLOCKED
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.lockSecond(DeadLock.java:64)
    INFO   | jvm 1    | WrapperManager Error:       - waiting on <0x0000000029c56c60> (a java.lang.Object) owned by "Locker-2" tid=18
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.lockFirst(DeadLock.java:83)
    INFO   | jvm 1    | WrapperManager Error:       - locked <0x000000002fcac6db> (a java.lang.Object)
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock.access$100(DeadLock.java:22)
    INFO   | jvm 1    | WrapperManager Error:     at org.tanukisoftware.wrapper.test.DeadLock$1.run(DeadLock.java:42)
    INFO   | jvm 1    | WrapperManager Error:
    INFO   | jvm 1    | WrapperManager Error: =============================
    STATUS | wrapper  | A Thread Deadlock was detected in the JVM.  Restarting JVM.
  • SIMPLE -

    JVM?部でWrapperManagerクラスが?? ??ドロ?クで呼び出されたスレ?ドやオブジェクト?簡単な概要だけを含? レポ?トを出力します?? 多くの場合?特によく知られた問題に関しては十??です??

    「SIMPLE?シンプル???出力?
    INFO   | jvm 1    | WrapperManager Error: Found 2 deadlocked threads!
    INFO   | jvm 1    | WrapperManager Error: =============================
    INFO   | jvm 1    | WrapperManager Error: "Locker-2" BLOCKED waiting on a java.lang.Object owned by "Locker-1"
    INFO   | jvm 1    | WrapperManager Error: "Locker-1" BLOCKED waiting on a java.lang.Object owned by "Locker-2"
    INFO   | jvm 1    | WrapperManager Error: =============================
    STATUS | wrapper  | A Thread Deadlock was detected in the JVM.  Restarting JVM.
  • NONE -

    JVM?部でWrapperManagerクラスが?? 全ての出力を抑えます?? これはシス??製品?利用に向いて?ます?? 問題?把握しており? たくさんのログ?報を望まな?、あるいは、保持する?要がな?、ケースに適して?ます?? そ?他?選択として、Wrapperプロセスは? トリガーされ?アクション? 発生した理由を提供するために? 常にシングル・エントリをログ化して?きます??

    「NONE?なし)??出力?
    STATUS | wrapper  | A Thread Deadlock was detected in the JVM.  Restarting JVM.

wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/exec_en.html100644 0 0 2035 12440202301 24544 0ustar 0 0 The WrapperManager.exec() function is a alternative to the Java-Runtime.exec() which has the disadvantage to use the on some platforms memory expensive fork() method to create a new process.

The problem on those platforms is, that if the Parent Process from which one wants to start a side process, fork() causes to clone the memory of the parent for the child.
This will double the used memory for a short time.
Given a fairly large application which is close to the systems memory quota, it might fail to just create a small application like ls or the memory is going to get swapped on the HD, which decreases the performance drastically.

Another issue is to ease bind or detach the child while starting from the parent.
If the Java Process terminates expected or unexpected the wrapper will clean all bind processes which haven't finished yet.



For better consistency the exec() function was implemented as close to the Runtime.exec() function in Java as possible. wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/exec_ja.html100644 0 0 3755 12440202301 24546 0ustar 0 0

?WrapperManager.exec()? 関数は? ?Java-Runtime.exec()?の代替え案です?? ?Java-Runtime.exec()?は?くつか?プラ?トフォー?で 新しいプロセスを生成する?に?fork()?メソ?ドを 利用してメモリを無?に消費する不利な点があります?? それら?プラ?トフォー?上での問題?? もし、サイド?プロセスを開始したいペアレント(親??ロセスの場合?? ?fork()?がチャイルド(子)用にペアレント(親??メモリのクローンを作?します?? これは、短?時間、消費メモリが?になります?? シス??・メモリ・割り当て量に近い、わりと大きいアプリケーションが与えられると? lsのような? 小さ?アプリケーションの作?にも失敗する可能性があります?? ある?は、ハードディスクへそ?メモリのスワ?ピングが発生する可能性もあり?パフォーマンスが劇?に低下することになります??

もう?つの問題としては、?アレント(親?から開始して?る間? チャイルド(子)?バインドや?タ?チを緩和することです?? もしJavaプロセスが?期?どおりにしろ、予想外にしろ、終?する場合?? Wrapperは、ま?終?して?な?全てのバインド?プロセスをクリーンします??

より良??貫性のために、可能な限り、Javaでの?Runtime.exec()?関数に近い? ?WrapperManager.exec()?関数が実?されました?

wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/frozen_en.html100644 0 0 2501 12440202301 25121 0ustar 0 0

Simulate JVM Hang

This test causes the Wrapper to think that the JVM has become hung. After 30 seconds, the Wrapper times out and decides that the JVM will not come back and restarts it.

Console Output:
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
jvm 1    | WARNING: Making JVM appear to be hung...
wrapper  | JVM appears hung: Timed out waiting for signal from JVM.
wrapper  | Java Virtual Machine did not exit on request, terminated
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/frozen_ja.html100644 0 0 2651 12440202301 25117 0ustar 0 0

JVMハングア?プ?シミュレーション

JVMハングア?プ?シミュレーション こ??ストでは、Wrapperに「JVMがハングア?プした?と思わせる?ストです?? 30秒後にタイ?アウトで、WrapperはJVMが復旧しな?と判断して、JVMを?起動させます??

コンソール出?:
wrapper  | --> Wrapper Started as Console
wrapper  | Launching a JVM...
jvm 1    | Initializing...
jvm 1    | Wrapper (Version 3.x.x)
jvm 1    |
jvm 1    | start()
jvm 1    | WARNING: Making JVM appear to be hung...
wrapper  | JVM appears hung: Timed out waiting for signal from JVM.
wrapper  | Java Virtual Machine did not exit on request, terminated
wrapper  | Launching a JVM...
jvm 2    | Initializing...
jvm 2    | Wrapper (Version 3.x.x)
jvm 2    |
jvm 2    | start()
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/mail_en.html100644 0 0 3336 12440202301 24547 0ustar 0 0 The Wrapper is able to send out alert emails to in response to certain events.
See the documentation of individual properties for details on their use.
Example (send email in response to JVM restarts):
# Common Event Email settings.
#wrapper.event.default.email.debug=TRUE
wrapper.event.default.email.smtp.host=smtp.mycompany.com
wrapper.event.default.email.smtp.port=25
wrapper.event.default.email.subject=[%WRAPPER_HOSTNAME%:%WRAPPER_NAME%:%WRAPPER_EVENT_NAME%] Event Notification
wrapper.event.default.email.sender=myapp-noreply@mycompany.com
wrapper.event.default.email.recipient=myapp-admin@mycompany.com
# Event specific settings.
wrapper.event.jvm_restart.email=TRUE
wrapper.event.jvm_restart.email.body=The JVM was restarted.\n\nPlease check on its status.\n

The properties are all of the form wrapper.event.<x>.email*
where x is one of the "Event Types" defined above or the keyword default.

Whenever a property is not specifically defined for any of the event names,
the default value will be used. This is useful for setting values which will be common to all event emails.

wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/mail_ja.html100644 0 0 3706 12440202301 24540 0ustar 0 0 Wrapperでは、あるイベントに反応して、アラート?知をメールで送ることができます?? 使?方などのさらに詳しくは、?別のプロパティの説明をご覧ください?
? (JVM再起動に応じてメール通知を?信する?)??
# Common Event Email settings.
#wrapper.event.default.email.debug=TRUE
wrapper.event.default.email.smtp.host=smtp.mycompany.com
wrapper.event.default.email.smtp.port=25
wrapper.event.default.email.subject=[%WRAPPER_HOSTNAME%:%WRAPPER_NAME%:%WRAPPER_EVENT_NAME%] Event Notification
wrapper.event.default.email.sender=myapp-noreply@mycompany.com
wrapper.event.default.email.recipient=myapp-admin@mycompany.com
# Event specific settings.
wrapper.event.jvm_restart.email=TRUE
wrapper.event.jvm_restart.email.body=The JVM was restarted.\n\nPlease check on its status.\n

こ?プロパティは??wrapper.event.<x>.email*?形式で? ?x」?部は、上記で定義され?イベント?種類??つ? ある?は、??default?デフォルト)??キーワードが入ります??

プロパティに何もイベント名が特別には定義されて?な?時??つでも?デフォルト?が適用されます?? 全てのイベント?メールに対して?般?な値を設定する?に便利です??

wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/out_of_mem_en.html100644 0 0 2327 12440202301 25755 0ustar 0 0

Out of Memory

The following example will monitor the JVM output and then restart the JVM automatically whenever a java.lang.OutOfMemoryError is thrown to the console. Depending on where in an application the error is thrown, it is not always possible to trap and handle the error in a useful way from within the JVM.

Filters work by monitoring the console output of the JVM. In order for a trigger to be fired by an exception, the Java application must print the message being filtered to the console.

Example:
wrapper.filter.trigger.1=java.lang.OutOfMemoryError
wrapper.filter.action.1=RESTART
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/out_of_mem_ja.html100644 0 0 2764 12440202301 25752 0ustar 0 0

Out of Memory

下記?例では、JVM出力をモニタリング?監視)して? ?java.lang.OutOfMemoryError?がコンソールへ投げられた時に?つでも?? JVMを?動的に再起動します?? エラーがアプリケーションのどこに投げられるか次第で変わります?で? ?ずしも?常にJVM?部からのエラーを検知して取り扱?ことができる」と??わけではありません?

フィルターは、JVMのコンソール出力をモニタリング?監視)することで動作します?? トリガーが例外で発動されるようにするために? Javaアプリケーションは、コンソールへフィルタリングされたメ?セージを表示させなければなりません?

Example:
wrapper.filter.trigger.1=java.lang.OutOfMemoryError
wrapper.filter.action.1=RESTART
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/service_en.html100644 0 0 15350 12440202301 25304 0ustar 0 0

Running as a Windows Service

When running as a Windows Service, the Application will be unable to show its Dialog. So this sample application is not very interesting. We can however do a few tests to verify that the Wrapper acts as a Windows Service correctly.

Install-<Your App>.bat
You will see the output:
wrapper  | <Your App> installed.

Once your application is installed as a service, we will want to start it.

net start <Your App>
You will see the output:
<Your App> service is starting.
<Your App> service was started successfully.

The service can be uninstalled by executing the following command:

Uninstall<Your App>-NT.bat
If the service is running, you will see the output:
wrapper  | Service is running.  Stopping it...
wrapper  | Waiting to stop...
wrapper  | <Your App> stopped.
wrapper  | <Your App> removed.

If you look at the contents of logs/wrapper.log, you will see output very similar to that of the console. Except this time, the start message informs you that the application is being started as a Service.

wrapper.log
wrapper  | 2001/12/06 17:34:21 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:34:21 | Launching a JVM...
jvm 1    | 2001/12/06 17:34:22 | Initializing...
jvm 1    | 2001/12/06 17:34:22 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:34:22 |
jvm 1    | 2001/12/06 17:34:22 | start()

Here are the results of several more actions that can take place on Windows Service:

User Logging out and then back in

A log entry is made when the user logs out, but the service is unaffected.

wrapper.log
wrapper  | 2001/12/06 17:39:39 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:39:40 | Launching a JVM...
jvm 1    | 2001/12/06 17:39:40 | Initializing...
jvm 1    | 2001/12/06 17:39:40 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:39:40 |
jvm 1    | 2001/12/06 17:39:41 | start()
wrapper  | 2001/12/06 17:40:07 | User logged out.  Ignored.
jvm 1    | 2001/12/06 17:40:07 | controlEvent(202)

Restarting the machine

This will result in a logout signal followed by a shutdown signal. The service will be shutdown gracefully and then come back after the machine restarts.

A log entry is made when the user logs out, but the service is unaffected.

wrapper.log
wrapper  | 2001/12/06 17:41:04 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:41:05 | Launching a JVM...
jvm 1    | 2001/12/06 17:41:05 | Initializing...
jvm 1    | 2001/12/06 17:41:05 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:41:05 |
jvm 1    | 2001/12/06 17:41:05 | start()
wrapper  | 2001/12/06 17:41:25 | User logged out.  Ignored.
jvm 1    | 2001/12/06 17:41:26 | controlEvent(202)
wrapper  | 2001/12/06 17:41:27 | Machine is shutting down.
jvm 1    | 2001/12/06 17:41:27 | controlEvent(203)
jvm 1    | 2001/12/06 17:41:28 | stop(0)
wrapper  | 2001/12/06 17:41:29 | <-- Wrapper Stopped
wrapper  | 2001/12/06 17:44:12 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:44:12 | Launching a JVM...
jvm 1    | 2001/12/06 17:44:17 | Initializing...
jvm 1    | 2001/12/06 17:44:21 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:44:21 |
jvm 1    | 2001/12/06 17:44:23 | start()
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/demo/html/service_ja.html100644 0 0 16716 12440202301 25303 0ustar 0 0

Windowsサービスの?つとして動か?

Windowsサービスの?つとして動かすとき?このプリケーションは?イアログを表示することができません? そ?ため、このサンプル・アプリケーションは、あまり面白くありませんが?? しかしながら、?達が???????ストをして? Windowsサービスの?つとして正しくWrapperが動作することを実証しました?

?初にすることは、このアプリケーションのインスト?ルです?? 次のコマンドを実行して、Windowsサービスの?つとして動かしてください??

Install-<Your App>.bat
こ?出力が見えます?
wrapper  | <Your App> installed.

?旦、アプリケーションがサービスの?つとしてインスト?ルしたら?? 早速?それをスタートしてみましょ??

net start <Your App>
こ?出力が見えま?
<Your App> service is starting.
<Your App> service was started successfully.

そ?サービスは、次のコマンドを実行して、アンインスト?ルすることができます?:

Uninstall<Your App>-NT.bat
もしサービスが実行中なら?、この出力が見えます?
wrapper  | Service is running.  Stopping it...
wrapper  | Waiting to stop...
wrapper  | <Your App> stopped.
wrapper  | <Your App> removed.

?logs/wrapper.log? の中身を見ると、このコンソールにとても類似した出力が見られると思います?? 今回を除き?そのスタート?メ?セージは、アプリケーションがサービスとして開始されたことを知らせて?ます??

wrapper.log
wrapper  | 2001/12/06 17:34:21 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:34:21 | Launching a JVM...
jvm 1    | 2001/12/06 17:34:22 | Initializing...
jvm 1    | 2001/12/06 17:34:22 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:34:22 |
jvm 1    | 2001/12/06 17:34:22 | start()

Windowsサービス上で起きる、いくつかその他?アクションの結果です?:

ユーザー・ログアウ? と そ?復帰

ユーザーのログアウトでログ・エントリが作?されますが、サービスには影響ありません?

wrapper.log
wrapper  | 2001/12/06 17:39:39 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:39:40 | Launching a JVM...
jvm 1    | 2001/12/06 17:39:40 | Initializing...
jvm 1    | 2001/12/06 17:39:40 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:39:40 |
jvm 1    | 2001/12/06 17:39:41 | start()
wrapper  | 2001/12/06 17:40:07 | User logged out.  Ignored.
jvm 1    | 2001/12/06 17:40:07 | controlEvent(202)

マシン再起?

これは、シャ?トダウン・シグナルに続く、ログアウト?シグナルの結果になります?? サービスがキレイにシャ?トダウンされると、?シン再起動?後?戻ってきます??

ユーザーのログアウトでログ・エントリが作?されますが、サービスには影響ありません?

wrapper.log
wrapper  | 2001/12/06 17:41:04 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:41:05 | Launching a JVM...
jvm 1    | 2001/12/06 17:41:05 | Initializing...
jvm 1    | 2001/12/06 17:41:05 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:41:05 |
jvm 1    | 2001/12/06 17:41:05 | start()
wrapper  | 2001/12/06 17:41:25 | User logged out.  Ignored.
jvm 1    | 2001/12/06 17:41:26 | controlEvent(202)
wrapper  | 2001/12/06 17:41:27 | Machine is shutting down.
jvm 1    | 2001/12/06 17:41:27 | controlEvent(203)
jvm 1    | 2001/12/06 17:41:28 | stop(0)
wrapper  | 2001/12/06 17:41:29 | <-- Wrapper Stopped
wrapper  | 2001/12/06 17:44:12 | --> Wrapper Started as Service
wrapper  | 2001/12/06 17:44:12 | Launching a JVM...
jvm 1    | 2001/12/06 17:44:17 | Initializing...
jvm 1    | 2001/12/06 17:44:21 | Wrapper (Version 3.x.x)
jvm 1    | 2001/12/06 17:44:21 |
jvm 1    | 2001/12/06 17:44:23 | start()
wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperControlEvent.java100644 0 0 12447 12440202301 26357 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperControlEvent are used to notify the listener whenever the native * wrapper code traps a system control signal against the Java process. * It is up to the listener to take any actions necessary. *

* The Wrapper will send this event to any registered listeners first, * then it will pass the control code to the WrapperListener.controlEvent * method. If the consume method is called, it will still be passed to * other WrapperEventListeners, but will not be passed to the * WrapperListener.controlEvent method. Other WrapperEventListeners should * check the isConsumed method to decide whether or not the even has already * been handled. *

* If the wrapper.ignore_signals property is set to true then the event will * still be fired, but its isConsumed() method will return true initially. *

* Possible values are: *

*
WrapperManager.WRAPPER_CTRL_C_EVENT
*
The user pressed CTRL-C in a command windown (Windows or UNIX). * Or the kill INT signal was received (UNIX).
*
WRAPPER_CTRL_CLOSE_EVENT
*
The user is trying to close the console in which the Wrapper is * running (Windows).
*
WRAPPER_CTRL_LOGOFF_EVENT
*
The user logged off (Windows).
*
WRAPPER_CTRL_SHUTDOWN_EVENT
*
The system is being shutdown (Windows).
*
WRAPPER_CTRL_TERM_EVENT *
The kill TERM signal was received (UNIX).
*
WRAPPER_CTRL_HUP_EVENT *
The kill HUP signal was received (UNIX).
*
* * @author Leif Mortenson */ public class WrapperControlEvent extends WrapperEvent { /** * Serial Version UID. */ private static final long serialVersionUID = -7033261694452001713L; /** The system control event. */ private int m_controlEvent; /** The name of the event. */ private String m_controlEventName; /** True if the event has been consumed. */ private boolean m_consumed; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperControlEvent. * * @param controlEvent Service control event. * @param controlEventName The name of the event. */ public WrapperControlEvent( int controlEvent, String controlEventName ) { m_controlEvent = controlEvent; m_controlEventName = controlEventName; } /*--------------------------------------------------------------- * WrapperEvent Methods *-------------------------------------------------------------*/ /** * Returns a set of event flags for which the event should be fired. * This value is compared with the mask supplied when when a * WrapperEventListener is registered to decide which listeners should * receive the event. *

* If subclassed, the return value of the super class should usually * be ORed with any additional flags. * * @return a set of event flags. */ public long getFlags() { return super.getFlags() | WrapperEventListener.EVENT_FLAG_CONTROL; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the system control event. *

* Possible values are: WrapperManager.WRAPPER_CTRL_C_EVENT, * WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, * WRAPPER_CTRL_SHUTDOWN_EVENT, WRAPPER_CTRL_TERM_EVENT, or * WRAPPER_CTRL_HUP_EVENT. * * @return The system control event. */ public int getControlEvent() { return m_controlEvent; } /** * Returns the name of the control event. * * @return The name of the control event. */ public String getControlEventName() { return m_controlEventName; } /** * Mark the event as consumed. This should be done if the event * has been handled. *

* On Windows, some events are sent both to the JVM and Wrapper processes. * Event if the CTRL-C event is ignored within the JVM, the Wrapper * process may still initiate a shutdown. */ public void consume() { m_consumed = true; } /** * Returns true if the event has been consumed. * * @return True if the event has been consumed. */ public boolean isConsumed() { return m_consumed; } /** * Returns a string representation of the event. * * @return A string representation of the event. */ public String toString() { return "WrapperControlEvent[controlEvent=" + getControlEvent() + ", controlEventName=" + getControlEventName() + ", consumed=" + isConsumed() + "]"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperCoreEvent.java100644 0 0 3656 12440202301 25611 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperCoreEvents are used to notify the listener of the internal * workings of the Wrapper. * * WARNING - Great care should be taken when receiving events of this type. * They are sent from within the Wrapper's internal timing thread. If the * listner takes too much time working with the event, Wrapper performance * could be adversely affected. If unsure, it is recommended that events * of this type not be included. * * @author Leif Mortenson */ public abstract class WrapperCoreEvent extends WrapperEvent { /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperCoreEvent. */ protected WrapperCoreEvent() { } /*--------------------------------------------------------------- * WrapperCoreEvent Methods *-------------------------------------------------------------*/ /** * Returns a set of event flags for which the event should be fired. * This value is compared with the mask supplied when when a * WrapperEventListener is registered to decide which listeners should * receive the event. *

* If subclassed, the return value of the super class should usually * be ORed with any additional flags. * * @return a set of event flags. */ public long getFlags() { return super.getFlags() | WrapperEventListener.EVENT_FLAG_CORE; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperEvent.java100644 0 0 3565 12440202301 24777 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.util.EventObject; import org.tanukisoftware.wrapper.WrapperManager; /** * WrapperEvents are used to notify WrapperEventListeners of various wrapper * related events. *

* For performance reasons, some event instances may be reused by the code * which fires them off. For this reason, references to the event should * never be referenced outside the scope of the WrapperListener.processEvent * method. * * @author Leif Mortenson */ public abstract class WrapperEvent extends EventObject { /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperEvent. */ protected WrapperEvent() { super( WrapperManager.class ); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns a set of event flags for which the event should be fired. * This value is compared with the mask supplied when when a * WrapperEventListener is registered to decide which listeners should * receive the event. *

* If subclassed, the return value of the super class should usually * be ORed with any additional flags. * * @return a set of event flags. */ public long getFlags() { return 0; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperEventListener.java100644 0 0 5326 12440202301 26502 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperEventListeners can be registered with the WrapperManager class * to receive WrapperEvents. * * @author Leif Mortenson */ public interface WrapperEventListener { /** * Enabling service events will cause the listener to receive * WrapperServiceEvents. These events pertain to the Wrapper as a * service. */ static long EVENT_FLAG_SERVICE = 0x1; /** * Enabling control events will cause the listener to receive * WrapperControlEvents. These events are thrown whenever the * Java process receives control events from the system. These * include CTRL-C, HALT, TERM signals etc. */ static long EVENT_FLAG_CONTROL = 0x2; /** * Enabling logging events will cause the listener to receive * WrapperLoggingEvents. These events are thrown in response * to certain logging events such as updates to the log file * name. */ static long EVENT_FLAG_LOGGING = 0x4; /** * Enabling core events will cause the listener to receive * WrapperCoreEvents. These events provide information on the internal * timing of the Wrapper. *

* WARNING - Great care should be taken when receiving events of this type. * They are sent from within the Wrapper's internal timing thread. If the * listner takes too much time working with the event, Wrapper performance * could be adversely affected. If unsure, it is recommended that events * of this type not be included. */ static long EVENT_FLAG_CORE = 0xf000000000000000L; /** * Called whenever a WrapperEvent is fired. The exact set of events that a * listener will receive will depend on the mask supplied when * WrapperManager.addWrapperEventListener was called to register the * listener. *

* Listener implementations should never assume that they will only receive * events of a particular type. To assure that events added to future * versions of the Wrapper do not cause problems with user code, events * should always be tested with "if ( event instanceof {EventClass} )" * before casting it to a specific event type. * * @param event WrapperEvent which was fired. */ void fired( WrapperEvent event ); } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperLogFileChangedEvent.java100644 0 0 3456 12440202301 27512 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.File; /** * WrapperLogFileChangedEvent are fired whenever the log file used by the * Wrapper is changed. This can happen due to nightly log rotation for * example. * * @author Leif Mortenson */ public class WrapperLogFileChangedEvent extends WrapperLoggingEvent { private final File m_logFile; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperLogFileChangedEvent. */ public WrapperLogFileChangedEvent( File logFile ) { m_logFile = logFile; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the updated log file name. * * @return The updated log file name. */ public File getLogFile() { return m_logFile; } /*--------------------------------------------------------------- * Method *-------------------------------------------------------------*/ /** * Returns a string representation of the event. * * @return A string representation of the event. */ public String toString() { return "WrapperLogFileChangedEvent[logFile=" + getLogFile() + "]"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperLoggingEvent.java100644 0 0 3206 12440202301 26276 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperLoggingEvents are used to notify the listener of events related * to logging such as updates to the log file name. * * @author Leif Mortenson */ public abstract class WrapperLoggingEvent extends WrapperEvent { /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperLoggingEvent. */ protected WrapperLoggingEvent() { } /*--------------------------------------------------------------- * WrapperLoggingEvent Methods *-------------------------------------------------------------*/ /** * Returns a set of event flags for which the event should be fired. * This value is compared with the mask supplied when when a * WrapperEventListener is registered to decide which listeners should * receive the event. *

* If subclassed, the return value of the super class should usually * be ORed with any additional flags. * * @return a set of event flags. */ public long getFlags() { return super.getFlags() | WrapperEventListener.EVENT_FLAG_LOGGING; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperPingEvent.java100644 0 0 3405 12440202301 25606 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperPingEvent are fired each time a ping is received from the Wrapper * process. This event is mainly useful for debugging and statistic * collection purposes. *

* WARNING - Great care should be taken when receiving events of this type. * They are sent from within the Wrapper's internal timing thread. If the * listner takes too much time working with the event, Wrapper performance * could be adversely affected. If unsure, it is recommended that events * of this type not be included. * * @author Leif Mortenson */ public class WrapperPingEvent extends WrapperCoreEvent { /** * Serial Version UID. */ private static final long serialVersionUID = 284255850873300689L; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperPingEvent. */ public WrapperPingEvent() { } /*--------------------------------------------------------------- * Method *-------------------------------------------------------------*/ /** * Returns a string representation of the event. * * @return A string representation of the event. */ public String toString() { return "WrapperPingEvent"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperServiceActionEvent.java100644 0 0 12744 12440202301 27475 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; /** * WrapperServicePauseResumeEvents are used to notify the listener that the Wrapper * is requesting that the Java application be paused or resumed. This does not * mean that it should exit, only that it should internally go into an idle state. * * See the wrapper.pausable and wrapper.pausable.stop_jvm properties for more * information. * * @author Leif Mortenson * * @since Wrapper 3.5.0 */ public abstract class WrapperServiceActionEvent extends WrapperServiceEvent { /** * Serial Version UID. */ private static final long serialVersionUID = 7901768955067874864L; /* * * Note - The following SOURCE_CODE_* values must match those in the wrapper.h file. * */ /** * Action result of a configured filter being fired. * See the wrapper.filter.action. property. */ public static final int SOURCE_CODE_FILTER = 1; /** * Action result of a command from a command file. * See the wrapper.commandfile property. */ public static final int SOURCE_CODE_COMMANDFILE = 2; /** * Action resulted from the Windows Service Manager. This can happen * from a number of sources including the command line, Service Control * Panel, etc. */ public static final int SOURCE_CODE_WINDOWS_SERVICE_MANAGER = 3; /** * Action result of a matched exit code. * See the wrapper.on_exit. property. */ public static final int SOURCE_CODE_ON_EXIT = 4; /** * Action result of a deadlock being detected. * See the wrapper.check.deadlock.action property. */ public static final int SOURCE_CODE_DEADLOCK = 10; /** * Action result of a configured timer being fired. * See the wrapper.timer..action property. */ public static final int SOURCE_CODE_TIMER = 21; /** * Action result of an event command's block timeout expired. * See the wrapper.event..command.block.action property. */ public static final int SOURCE_CODE_COMMAND_BLOCK_TIMEOUT = 22; /** * Code which keeps track of how the service was paused. */ private int m_actionSourceCode; /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ /** * Returns the name of the specified Source Code. * * @param actionSourceCode The Source Code whose name is being requested. * * @return The name of the Source Code. */ public static String getSourceCodeName( int actionSourceCode ) { switch( actionSourceCode ) { case SOURCE_CODE_FILTER: return WrapperManager.getRes().getString( "Filter Action" ); case SOURCE_CODE_COMMANDFILE: return WrapperManager.getRes().getString( "Command File Action" ); case SOURCE_CODE_WINDOWS_SERVICE_MANAGER: return WrapperManager.getRes().getString( "Windows Service Manager" ); case SOURCE_CODE_ON_EXIT: return WrapperManager.getRes().getString( "On Exit Action" ); case SOURCE_CODE_DEADLOCK: return WrapperManager.getRes().getString( "Deadlock Action" ); case SOURCE_CODE_TIMER: return WrapperManager.getRes().getString( "Timer Action" ); case SOURCE_CODE_COMMAND_BLOCK_TIMEOUT: return WrapperManager.getRes().getString( "Block Timeout Action" ); default: return WrapperManager.getRes().getString( "Unknown Code {0}", new Integer( actionSourceCode ) ); } } /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperServiceActionEvent. * * @param actionSourceCode Source Code specifying where the action originated. */ public WrapperServiceActionEvent( int actionSourceCode ) { m_actionSourceCode = actionSourceCode; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the Source Code describing where the event originated. * * @return The Source Code. */ public int getSourceCode() { return m_actionSourceCode; } /** * Returns the Source Code name. * * @return The Source Code name. */ public String getSourceCodeName() { return getSourceCodeName( m_actionSourceCode ); } /** * Returns a string representation of the event. * * @return A string representation of the event. */ public String toString() { return "WrapperServiceActionEvent[actionSourceCode=" + getSourceCodeName() + "]"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperServiceControlEvent.java100644 0 0 10244 12440202301 27671 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperServiceControlEvents are used to notify the listener whenever a * Service Control Event is received by the service. These events will * only be fired on Windows platforms when the Wrapper is running as a * service. * *

*
WrapperManager.SERVICE_CONTROL_CODE_STOP (1)
*
The service was requested to stop.
*
WrapperManager.SERVICE_CONTROL_CODE_PAUSE (2)
*
The system requested that the service be paused.
*
WrapperManager.SERVICE_CONTROL_CODE_CONTINUE (3)
*
The system requested that the paused service be resumed.
*
WrapperManager.SERVICE_CONTROL_CODE_INTERROGATE (4)
*
The service manager queried the service to make sure it is still alive.
*
WrapperManager.SERVICE_CONTROL_CODE_SHUTDOWN (5)
*
The system is shutting down.
*
User code (128-255)
*
User defined code.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_QUERYSUSPEND (3328)
*
The system being suspended.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_QUERYSUSPENDFAILED (3330)
*
Permission to suspend the computer was denied by a process.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_SUSPEND (3332)
*
The computer is about to enter a suspended state.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_RESUMECRITICAL (3334)
*
The system has resumed operation. This event can indicate that some or * all applications did not receive a SERVICE_CONTROL_CODE_POWEREVENT_SUSPEND * event.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_RESUMESUSPEND (3335)
*
The system has resumed operation after being suspended.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_BATTERYLOW (3337)
*
The battery power is low.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_POWERSTATUSCHANGE (3338)
*
There is a change in the power status of the computer, such as a * switch from battery power to A/C.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_OEMEVENT (3339)
*
The APM BIOS has signaled an APM OEM event.
*
WrapperManager.SERVICE_CONTROL_CODE_POWEREVENT_RESUMEAUTOMATIC (3346)
*
The computer has woken up automatically to handle an event.
*
* * @author Leif Mortenson */ public class WrapperServiceControlEvent extends WrapperServiceEvent { /** * Serial Version UID. */ private static final long serialVersionUID = -8642470717850552167L; /** The event code of the Service Control Code. */ private int m_serviceControlCode; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperServiceControlEvent. * * @param serviceControlCode Service Control Code. */ public WrapperServiceControlEvent( int serviceControlCode ) { m_serviceControlCode = serviceControlCode; } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the event code of the Service Control Code. * * @return The event code of the Service Control Code. */ public int getServiceControlCode() { return m_serviceControlCode; } /** * Returns a string representation of the event. * * @return A string representation of the event. */ public String toString() { return "WrapperServiceControlEvent[serviceControlCode=" + getServiceControlCode() + "]"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperServiceEvent.java100644 0 0 3133 12440202301 26307 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperServiceEvents are used to notify the listener of events related * the service. * * @author Leif Mortenson */ public abstract class WrapperServiceEvent extends WrapperEvent { /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperServiceEvent. */ protected WrapperServiceEvent() { } /*--------------------------------------------------------------- * WrapperEvent Methods *-------------------------------------------------------------*/ /** * Returns a set of event flags for which the event should be fired. * This value is compared with the mask supplied when when a * WrapperEventListener is registered to decide which listeners should * receive the event. *

* If subclassed, the return value of the super class should usually * be ORed with any additional flags. * * @return a set of event flags. */ public long getFlags() { return super.getFlags() | WrapperEventListener.EVENT_FLAG_SERVICE; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperServicePauseEvent.java100644 0 0 3534 12440202301 27312 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperServicePauseEvents are used to notify the listener that the Wrapper * is requesting that the Java application be paused. This does not mean that * it should exit, only that it should internally go into an idle state. * * See the wrapper.pausable and wrapper.pausable.stop_jvm properties for more * information. * * @author Leif Mortenson * * @since Wrapper 3.5.0 */ public class WrapperServicePauseEvent extends WrapperServiceActionEvent { /** * Serial Version UID. */ private static final long serialVersionUID = 1308747091110200773L; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperServicePauseEvent. * * @param actionSourceCode Source Code specifying where the pause action originated. */ public WrapperServicePauseEvent( int actionSourceCode ) { super( actionSourceCode ); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns a string representation of the event. * * @return A string representation of the event. */ public String toString() { return "WrapperServicePauseEvent[actionSourceCode=" + getSourceCodeName() + "]"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperServiceResumeEvent.java100644 0 0 3377 12440202301 27502 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperServiceResumeEvents are used to notify the listener that the Wrapper * is requesting that the Java application be resumed. * * See the wrapper.pausable and wrapper.pausable.stop_jvm properties for more * information. * * @author Leif Mortenson * * @since Wrapper 3.5.0 */ public class WrapperServiceResumeEvent extends WrapperServiceActionEvent { /** * Serial Version UID. */ private static final long serialVersionUID = 338313484021328312L; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperServiceResumeEvent. * * @param actionSourceCode Source Code specifying where the resume action originated. */ public WrapperServiceResumeEvent( int actionSourceCode ) { super( actionSourceCode ); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns a string representation of the event. * * @return A string representation of the event. */ public String toString() { return "WrapperServiceResumeEvent[actionSourceCode=" + getSourceCodeName() + "]"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/event/WrapperTickEvent.java100644 0 0 5354 12440202301 25610 0ustar 0 0 package org.tanukisoftware.wrapper.event; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * WrapperPingEvent are fired each time a ping is received from the Wrapper * process. This event is mainly useful for debugging and statistic * collection purposes. *

* WARNING - Great care should be taken when receiving events of this type. * They are sent from within the Wrapper's internal timing thread. If the * listner takes too much time working with the event, Wrapper performance * could be adversely affected. If unsure, it is recommended that events * of this type not be included. * * @author Leif Mortenson */ public abstract class WrapperTickEvent extends WrapperCoreEvent { /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperTickEvent. */ protected WrapperTickEvent() { } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the tick count at the point the event is fired. * * @return The tick count at the point the event is fired. */ public abstract int getTicks(); /** * Returns the offset between the tick count used by the Wrapper for time * keeping and the tick count generated directly from the system time. *

* This will be 0 in most cases. But will be a positive value if the * system time is ever set back for any reason. It will be a negative * value if the system time is set forward or if the system is under * heavy load. If the wrapper.use_system_time property is set to TRUE * then the Wrapper will be using the system tick count for internal * timing and this value will always be 0. * * @return The tick count offset. */ public abstract int getTickOffset(); /*--------------------------------------------------------------- * Method *-------------------------------------------------------------*/ /** * Returns a string representation of the event. * * @return A string representation of the event. */ public String toString() { return "WrapperTickEvent[ticks=" + getTicks() + ", tickOffset=" + getTickOffset() + "]"; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/jmx/WrapperManager.java100644 0 0 17137 12440202301 24765 0ustar 0 0 package org.tanukisoftware.wrapper.jmx; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * @author Leif Mortenson */ public class WrapperManager implements WrapperManagerMBean { /*--------------------------------------------------------------- * WrapperManagerMBean Methods *-------------------------------------------------------------*/ /** * Obtain the current version of Wrapper. * * @return The version of the Wrapper. */ public String getVersion() { return org.tanukisoftware.wrapper.WrapperManager.getVersion(); } /** * Obtain the build time of Wrapper. * * @return The time that the Wrapper was built. */ public String getBuildTime() { return org.tanukisoftware.wrapper.WrapperManager.getBuildTime(); } /** * Returns the Id of the current JVM. JVM Ids increment from 1 each time * the wrapper restarts a new one. * * @return The Id of the current JVM. */ public int getJVMId() { return org.tanukisoftware.wrapper.WrapperManager.getJVMId(); } /** * Returns true if the current Wrapper edition has support for Professional * Edition features. * * @return True if professional features are supported. */ public boolean isProfessionalEdition() { return org.tanukisoftware.wrapper.WrapperManager.isProfessionalEdition(); } /** * Returns true if the current Wrapper edition has support for Standard * Edition features. * * @return True if standard features are supported. */ public boolean isStandardEdition() { return org.tanukisoftware.wrapper.WrapperManager.isStandardEdition(); } /** * Sets the title of the console in which the Wrapper is running. This * is currently only supported on Windows platforms. *

* As an alternative, it is also possible to set the console title from * within the wrapper.conf file using the wrapper.console.title property. * * @param title The new title. The specified string will be encoded * to a byte array using the default encoding for the * current platform. */ public void setConsoleTitle( String title ) { org.tanukisoftware.wrapper.WrapperManager.setConsoleTitle( title ); } /** * Returns the PID of the Wrapper process. * * A PID of 0 will be returned if the JVM was launched standalone. * * This value can also be obtained using the 'wrapper.pid' system property. * * @return The PID of the Wrpper process. */ public int getWrapperPID() { return org.tanukisoftware.wrapper.WrapperManager.getWrapperPID(); } /** * Returns the PID of the Java process. * * A PID of 0 will be returned if the native library has not been initialized. * * This value can also be obtained using the 'wrapper.java.pid' system property. * * @return The PID of the Java process. */ public int getJavaPID() { return org.tanukisoftware.wrapper.WrapperManager.getJavaPID(); } /** * Requests that the current JVM process request a thread dump. This is * the same as pressing CTRL-BREAK (under Windows) or CTRL-\ (under Unix) * in the the console in which Java is running. This method does nothing * if the native library is not loaded. */ public void requestThreadDump() { org.tanukisoftware.wrapper.WrapperManager.requestThreadDump(); } /** * Returns true if the JVM was launched by the Wrapper application. False * if the JVM was launched manually without the Wrapper controlling it. * * @return True if the current JVM was launched by the Wrapper. */ public boolean isControlledByNativeWrapper() { return org.tanukisoftware.wrapper.WrapperManager.isControlledByNativeWrapper(); } /** * Returns true if the Wrapper was launched as an NT service on Windows or * as a daemon process on UNIX platforms. False if launched as a console. * This can be useful if you wish to display a user interface when in * Console mode. On UNIX platforms, this is not as useful because an * X display may not be visible even if launched in a console. * * @return True if the Wrapper is running as an NT service or daemon * process. */ public boolean isLaunchedAsService() { return org.tanukisoftware.wrapper.WrapperManager.isLaunchedAsService(); } /** * Returns true if the wrapper.debug property, or any of the logging * channels are set to DEBUG in the wrapper configuration file. Useful * for deciding whether or not to output certain information to the * console. * * @return True if the Wrapper is logging any Debug level output. */ public boolean isDebugEnabled() { return org.tanukisoftware.wrapper.WrapperManager.isDebugEnabled(); } /** * Tells the native wrapper that the JVM wants to restart, then informs * all listeners that the JVM is about to shutdown before killing the JVM. *

* The restart is actually performed in a background thread allowing JMX * a chance to respond to the client. */ public void restart() { // This action normally will not return, so launch it in a background // thread giving JMX a chance to return a response to its client. new Thread() { public void run() { try { Thread.sleep( 1000 ); } catch ( InterruptedException e ) { } org.tanukisoftware.wrapper.WrapperManager.restart(); } }.start(); } /** * Tells the native wrapper that the JVM wants to shut down, then informs * all listeners that the JVM is about to shutdown before killing the JVM. *

* The stop is actually performed in a background thread allowing JMX * a chance to respond to the client. * * @param exitCode The exit code that the Wrapper will return when it exits. */ public void stop( final int exitCode ) { // This action normally will not return, so launch it in a background // thread giving JMX a chance to return a response to its client. new Thread() { public void run() { try { Thread.sleep( 1000 ); } catch ( InterruptedException e ) { } org.tanukisoftware.wrapper.WrapperManager.stop( exitCode ); } }.start(); } /** * Returns true if the ShutdownHook for the JVM has already been triggered. * Some code needs to know whether or not the system is shutting down. * * @return True if the ShutdownHook for the JVM has already been triggered. */ public boolean getHasShutdownHookBeenTriggered() { return org.tanukisoftware.wrapper.WrapperManager.hasShutdownHookBeenTriggered(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/jmx/WrapperManagerMBean.java100644 0 0 12163 12440202301 25662 0ustar 0 0 package org.tanukisoftware.wrapper.jmx; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * @author Leif Mortenson */ public interface WrapperManagerMBean { /** * Obtain the current version of Wrapper. * * @return The version of the Wrapper. */ String getVersion(); /** * Obtain the build time of Wrapper. * * @return The time that the Wrapper was built. */ String getBuildTime(); /** * Returns the Id of the current JVM. JVM Ids increment from 1 each time * the wrapper restarts a new one. * * @return The Id of the current JVM. */ int getJVMId(); /** * Returns true if the current Wrapper edition has support for Professional * Edition features. * * @return True if professional features are supported. */ boolean isProfessionalEdition(); /** * Returns true if the current Wrapper edition has support for Standard * Edition features. * * @return True if standard features are supported. */ boolean isStandardEdition(); /** * Sets the title of the console in which the Wrapper is running. This * is currently only supported on Windows platforms. *

* As an alternative, it is also possible to set the console title from * within the wrapper.conf file using the wrapper.console.title property. * * @param title The new title. The specified string will be encoded * to a byte array using the default encoding for the * current platform. */ void setConsoleTitle( String title ); /** * Returns the PID of the Wrapper process. * * A PID of 0 will be returned if the JVM was launched standalone. * * This value can also be obtained using the 'wrapper.pid' system property. * * @return The PID of the Wrpper process. */ int getWrapperPID(); /** * Returns the PID of the Java process. * * A PID of 0 will be returned if the native library has not been initialized. * * This value can also be obtained using the 'wrapper.java.pid' system property. * * @return The PID of the Java process. */ int getJavaPID(); /** * Requests that the current JVM process request a thread dump. This is * the same as pressing CTRL-BREAK (under Windows) or CTRL-\ (under Unix) * in the the console in which Java is running. This method does nothing * if the native library is not loaded. */ void requestThreadDump(); /** * Returns true if the JVM was launched by the Wrapper application. False * if the JVM was launched manually without the Wrapper controlling it. * * @return True if the current JVM was launched by the Wrapper. */ boolean isControlledByNativeWrapper(); /** * Returns true if the Wrapper was launched as an NT service on Windows or * as a daemon process on UNIX platforms. False if launched as a console. * This can be useful if you wish to display a user interface when in * Console mode. On UNIX platforms, this is not as useful because an * X display may not be visible even if launched in a console. * * @return True if the Wrapper is running as an NT service or daemon * process. */ boolean isLaunchedAsService(); /** * Returns true if the wrapper.debug property, or any of the logging * channels are set to DEBUG in the wrapper configuration file. Useful * for deciding whether or not to output certain information to the * console. * * @return True if the Wrapper is logging any Debug level output. */ boolean isDebugEnabled(); /** * Tells the native wrapper that the JVM wants to restart, then informs * all listeners that the JVM is about to shutdown before killing the JVM. *

* The restart is actually performed in a background thread allowing JMX * a chance to respond to the client. */ void restart(); /** * Tells the native wrapper that the JVM wants to shut down, then informs * all listeners that the JVM is about to shutdown before killing the JVM. *

* The stop is actually performed in a background thread allowing JMX * a chance to respond to the client. * * @param exitCode The exit code that the Wrapper will return when it exits. */ void stop( int exitCode ); /** * Returns true if the ShutdownHook for the JVM has already been triggered. * Some code needs to know whether or not the system is shutting down. * * @return True if the ShutdownHook for the JVM has already been triggered. */ boolean getHasShutdownHookBeenTriggered(); } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/jmx/WrapperManagerTesting.java100644 0 0 5357 12440202301 26304 0ustar 0 0 package org.tanukisoftware.wrapper.jmx; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * @author Leif Mortenson */ public class WrapperManagerTesting implements WrapperManagerTestingMBean { /*--------------------------------------------------------------- * WrapperManagerTestingMBean Methods *-------------------------------------------------------------*/ /** * Causes the WrapperManager to go into a state which makes the JVM appear * to be hung when viewed from the native Wrapper code. Does not have * any effect when the JVM is not being controlled from the native * Wrapper. */ public void appearHung() { org.tanukisoftware.wrapper.WrapperManager.appearHung(); } /** * Cause an access violation within native JNI code. This currently causes * the access violation by attempting to write to a null pointer. */ public void accessViolationNative() { // This action normally will not return, so launch it in a background // thread giving JMX a chance to return a response to its client. new Thread() { public void run() { try { Thread.sleep( 1000 ); } catch ( InterruptedException e ) { } org.tanukisoftware.wrapper.WrapperManager.accessViolationNative(); } }.start(); } /** * Tells the native wrapper that the JVM wants to shut down and then * promptly halts. Be careful when using this method as an application * will not be given a chance to shutdown cleanly. * * @param exitCode The exit code that the Wrapper will return when it exits. */ public void stopImmediate( final int exitCode ) { // This action normally will not return, so launch it in a background // thread giving JMX a chance to return a response to its client. new Thread() { public void run() { try { Thread.sleep( 1000 ); } catch ( InterruptedException e ) { } org.tanukisoftware.wrapper.WrapperManager.stopImmediate( exitCode ); } }.start(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/jmx/WrapperManagerTestingMBean.java100644 0 0 3174 12440202301 27202 0ustar 0 0 package org.tanukisoftware.wrapper.jmx; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * This MBean interface provides access to a number of actions which can be * useful for testing how well an application responds to JVM crashes. It * has been broken out frtom the WrapperManagerMBean interface so system * administrators can easily disable the testing functions. * * @author Leif Mortenson */ public interface WrapperManagerTestingMBean { /** * Causes the WrapperManager to go into a state which makes the JVM appear * to be hung when viewed from the native Wrapper code. Does not have * any effect when the JVM is not being controlled from the native * Wrapper. */ void appearHung(); /** * Cause an access violation within native JNI code. This currently causes * the access violation by attempting to write to a null pointer. */ void accessViolationNative(); /** * Tells the native wrapper that the JVM wants to shut down and then * promptly halts. Be careful when using this method as an application * will not be given a chance to shutdown cleanly. * * @param exitCode The exit code that the Wrapper will return when it exits. */ void stopImmediate( int exitCode ); } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/resources/ResourceManager.java100644 0 0 20631 12440202301 26341 0ustar 0 0 package org.tanukisoftware.wrapper.resources; /* * Copyright (c) 1999, 2010 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.org/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.util.Hashtable; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.text.MessageFormat; /** * Some helper functions for handling i18n issues. One instance of this class * should be created for each resource.

* * The ResourceManager is created by a call to getResourceManager(). * The (optional) parameter is the name of the desired resource, not including the * .properties suffix. * * For example,

* * ResourceManager res = getResourceBundle(); * *

to get the default resources, or

* * ResourceManager res = getResourceBundle("sql"); * *

* to load the resources in sql.properties. * * To use the ResourceManager make a call to any of the format() * methods. If a string is not found in the bundle the key is returned and a * message is logged to the debug channel for this class. * * @author Leif Mortenson */ public class ResourceManager { private static Hashtable m_resources = new Hashtable(); /** * Whenever the Default Locale of the JVM is changed, then any existing * resource bundles will need to update their values. The * _classRefreshCounter static variable gets updated whenever a refresh * is done. The m_refreshCounter variable then is used to tell whether * an individual ResourceManager is up to date or not. */ private int m_refreshCounter; private static int m_staticRefreshCounter = 0; /** * The ResourceBundle for this locale. */ private ResourceBundle m_bundle; private String m_bundleName; /** * Private Constructor. */ private ResourceManager( String resourceName ) { // Resolve the bundle name based on this class so that it will work correctly with obfuscators. String className = this.getClass().getName(); // Strip off the class name at the end, keeping the ending '.' int pos = className.lastIndexOf( '.' ); if ( pos > 0 ) { m_bundleName = className.substring( 0, pos + 1 ); } else { m_bundleName = ""; } m_bundleName += resourceName; // Now load the bundle for the current Locale refreshBundle(); } private void refreshBundle() { try { m_bundle = ResourceBundle.getBundle( m_bundleName ); } catch ( MissingResourceException e ) { System.out.println( e ); } m_refreshCounter = m_staticRefreshCounter; } /** * Returns the default resource manager. * An instance of the ResourceManager class is created the first * time the method is called. */ public static ResourceManager getResourceManager() { return getResourceManager( null ); } /** * Returns the named resource manager. * An instance of the ResourceManager class is created the first * time the method is called. * * @param resourceName The name of the desired resource */ public static synchronized ResourceManager getResourceManager( String resourceName ) { if ( resourceName == null ) { resourceName = "resource"; } ResourceManager resource = (ResourceManager)m_resources.get( resourceName ); if ( resource == null ) { resource = new ResourceManager( resourceName ); m_resources.put( resourceName, resource ); } return resource; } /** * Clears the resource manager's cache of bundles (this should be called * if the default locale for the application changes). */ public static synchronized void refresh() { m_resources = new Hashtable(); m_staticRefreshCounter++; } private String getString( String key ) { // Make sure that the ResourceManager is up to date in a thread safe way synchronized(this) { if ( m_refreshCounter != m_staticRefreshCounter ) { refreshBundle(); } } String msg; if ( m_bundle == null ) { msg = key; } else { try { msg = m_bundle.getString( key ); } catch ( MissingResourceException ex ) { msg = key; System.out.println( key + " is missing from resource bundle \"" + m_bundleName + "\"" ); } } return msg; } /** * Returns a string that has been obtained from the resource manager * * @param key The string that is the key to the translated message * */ public String format( String key ) { return getString( key ); } /** * Returns a string that has been obtained from the resource manager then * formatted using the passed parameters. * * @param pattern The string that is the key to the translated message * @param o0 The param passed to format replaces {0} * */ public String format( String pattern, Object o0 ) { return MessageFormat.format( getString( pattern ), new Object[] { o0 } ); } /** * Returns a string that has been obtained from the resource manager then * formatted using the passed parameters. * * @param pattern The string that is the key to the translated message * @param o0 The param passed to format replaces {0} * @param o1 The param passed to format replaces {1} * */ public String format( String pattern, Object o0, Object o1 ) { return MessageFormat.format( getString( pattern ), new Object[] { o0,o1 } ); } /** * Returns a string that has been obtained from the resource manager then * formatted using the passed parameters. * * @param pattern The string that is the key to the translated message * @param o0 The param passed to format replaces {0} * @param o1 The param passed to format replaces {1} * @param o2 The param passed to format replaces {2} * */ public String format( String pattern, Object o0, Object o1, Object o2 ) { return MessageFormat.format( getString( pattern ), new Object[] { o0,o1,o2 } ); } /** * Returns a string that has been obtained from the resource manager then * formatted using the passed parameters. * * @param pattern The string that is the key to the translated message * @param o0 The param passed to format replaces {0} * @param o1 The param passed to format replaces {1} * @param o2 The param passed to format replaces {2} * @param o3 The param passed to format replaces {3} * */ public String format( String pattern, Object o0, Object o1, Object o2, Object o3 ) { return MessageFormat.format( getString( pattern ), new Object[] { o0,o1,o2,o3 } ); } // add more if you need them... } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/resources/resource.properties100644 0 0 1732 12440202301 26342 0ustar 0 0 ################################################# # # # Message keys are in alphabetical order. # # # ################################################# # Errors #======== BAD_CPU_TIMEOUT=''{0}'' is not a valid value for ''wrapper.cpu.timeout''. BAD_PORT=''{0}'' is not a valid value for ''wrapper.port''. BUSY_PORT=Unable to start Wrapper server: Port {0,number,#####} already in use FREE_PORT=The server port {0} has been freed: Wrapper server started MISSING_PORT=The 'wrapper.port' system property was not set. SERVER_DAEMON_DIED=Server daemon died! # Warnings #========== SERVER_DAEMON_KILLED=Server daemon killed # Info #====== SERVER_DAEMON_SHUT_DOWN=Server daemon shut down SERVER_UP_AND_WAITING=Wrapper up and waiting for connections... LOGGING_TO_STANDARD_OUT=Logging to standard out LOGGING_TO_{0}=Logging to {0} # Others #======== PROBLEM_OPENING_{0}=Problem opening {0} wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/security/WrapperEventPermission.java100644 0 0 32555 12440202301 27617 0ustar 0 0 package org.tanukisoftware.wrapper.security; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.security.Permission; import java.security.PermissionCollection; import java.util.Enumeration; import java.util.Vector; import java.util.StringTokenizer; import org.tanukisoftware.wrapper.WrapperManager; /** * WrapperEventPermissions are used to grant the right to register to start * receiving events from the Wrapper. *

* Some of these permissions can result in performance degredations if used * impropperly. *

* The following are examples of how to specify the permission within a policy * file. *

 *   grant codeBase "file:../lib/-" {
 *     // Grant various permissions to a specific service.
 *     permission org.tanukisoftware.wrapper.security.WrapperEventPermission "service";
 *     permission org.tanukisoftware.wrapper.security.WrapperEventPermission "service, core";
 *     permission org.tanukisoftware.wrapper.security.WrapperEventPermission "*";
 *   };
 * 
*

* Possible eventTypes include the following: * * * * * * * * * * * * * * * * * * * * * * * * *
Permission Event Type NameWhat the Permission AllowsRisks of Allowing this Permission
serviceRegister to obtain events whenever the Wrapper service receives any service events.Malicious code could receive this event and never return and thus cause performance * and timeout problems with the Wrapper. Normal use of these events are quite safe * however.
controlRegister to obtain events whenever the Wrapper receives any system control signals.Malicious code could trap and consome control events, thus preventing an application * from being shut down cleanly.
coreRegister to obtain events on the core workings of the Wrapper.Malicious code or even well meaning code can greatly affect the performance of * the Wrapper simply by handling these methods slowly. Some of these events are * fired from within the core timing code of the Wrapper. They are useful for * testing and performance checks, but in general they should not be used by * most applications. *
* * @author Leif Mortenson */ public class WrapperEventPermission extends Permission { /** * Serial Version UID. */ private static final long serialVersionUID = 8916489326587298168L; public static String EVENT_TYPE_SERVICE = "service"; public static String EVENT_TYPE_CONTROL = "control"; public static String EVENT_TYPE_CORE = "core"; private static int MASK_SERVICE = 1; private static int MASK_CONTROL = 2; private static int MASK_CORE = 65536; private static int MASK_ALL = MASK_SERVICE | MASK_CONTROL | MASK_CORE; private int m_eventTypeMask; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperEventPermission for the specified service. * * @param eventTypes The event type or event types to be registered. */ public WrapperEventPermission( String eventTypes ) { super( "*" ); m_eventTypeMask = buildEventTypeMask( eventTypes ); } /*--------------------------------------------------------------- * Permission Methods *-------------------------------------------------------------*/ /** * Checks two Permission objects for equality. *

* Do not use the equals method for making access control decisions; use * the implies method. * * @param obj The object we are testing for equality with this object. * * @return True if both Permission objects are equivalent. */ public boolean equals( Object obj ) { if ( obj == this ) { return true; } if ( !( obj instanceof WrapperEventPermission ) ) { return false; } WrapperEventPermission wsp = (WrapperEventPermission)obj; return ( m_eventTypeMask == wsp.m_eventTypeMask ) && getName().equals( wsp.getName() ); } /** * Return the canonical string representation of the eventTypes. * Always returns present eventTypes in the following order: * start, stop, pause, continue, interrogate. userCode. * * @return The canonical string representation of the eventTypes. */ public String getActions() { StringBuffer sb = new StringBuffer(); boolean first = true; if ( ( m_eventTypeMask & MASK_SERVICE ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( EVENT_TYPE_SERVICE ); } if ( ( m_eventTypeMask & MASK_CONTROL ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( EVENT_TYPE_CONTROL ); } if ( ( m_eventTypeMask & MASK_CORE ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( EVENT_TYPE_CORE ); } return sb.toString(); } /** * Checks if this WrapperEventPermission object "implies" the * specified permission. *

* More specifically, this method returns true if:

*

    *
  • p2 is an instanceof FilePermission,

    *

  • p2's eventTypes are a proper subset of this object's eventTypes, * and

    *

  • p2's service name is implied by this object's service name. * For example, "MyApp*" implies "MyApp". *
* * @param p2 the permission to check against. * * @return true if the specified permission is implied by this object, */ public boolean implies( Permission p2 ) { if ( !( p2 instanceof WrapperEventPermission ) ) { return false; } WrapperEventPermission wsp = (WrapperEventPermission)p2; // we get the effective mask. i.e., the "and" of this and that. // They must be equal to that.mask for implies to return true. return ( ( m_eventTypeMask & wsp.m_eventTypeMask ) == wsp.m_eventTypeMask ) && impliesIgnoreEventTypeMask( wsp ); } /** * Returns an custom WECollection implementation of a PermissionCollection. */ public PermissionCollection newPermissionCollection() { return new WECollection(); } /** * Returns the hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { return getName().hashCode(); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the eventType mask of the Permission. * * @return The eventType mask of the Permission. */ int getActionMask() { return m_eventTypeMask; } /** * Tests whether this permissions implies another without taking the * eventType mask into account. * * @param p2 The permission to check against. * * @return True if the specified permission is implied by this object. */ boolean impliesIgnoreEventTypeMask( WrapperEventPermission p2 ) { if ( getName().equals( p2.getName() ) ) { return true; } if ( p2.getName().endsWith( "*" ) ) { if ( getName().startsWith( p2.getName().substring( 0, p2.getName().length() - 1 ) ) ) { return true; } } return false; } /** * Builds an event type mask given a comma separated list of eventTypes. * * @param eventTypes The list of event types. * * @return The event type mask. */ private int buildEventTypeMask( String eventTypes ) { // Check for the constants first as they are used internally. if ( eventTypes == EVENT_TYPE_SERVICE ) { return MASK_SERVICE; } else if ( eventTypes == EVENT_TYPE_CONTROL ) { return MASK_CONTROL; } else if ( eventTypes == EVENT_TYPE_CORE ) { return MASK_CORE; } else if ( eventTypes.equals( "*" ) ) { return MASK_ALL; } int mask = 0; StringTokenizer st = new StringTokenizer( eventTypes, "," ); while ( st.hasMoreTokens() ) { String eventType = st.nextToken(); if ( eventType.equals( EVENT_TYPE_SERVICE ) ) { mask |= MASK_SERVICE; } else if ( eventType.equals( EVENT_TYPE_CONTROL ) ) { mask |= MASK_CONTROL; } else if ( eventType.equals( EVENT_TYPE_CORE ) ) { mask |= MASK_CORE; } else { throw new IllegalArgumentException( WrapperManager.getRes().getString("Invalid permission eventType: \"{0}\"", eventType ) ); } } return mask; } } final class WECollection extends PermissionCollection { /** * Serial Version UID. */ private static final long serialVersionUID = -5183704982261198435L; private Vector m_permissions = new Vector(); /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates an empty WECollection. */ public WECollection() { } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Adds a permission to the FilePermissions. The key for the hash is * permission.path. * * @param permission The Permission object to add. * * @exception IllegalArgumentException If the permission is not a * FilePermission * * @exception SecurityException If this FilePermissionCollection object * has been marked readonly */ public void add( Permission permission ) { if ( !( permission instanceof WrapperEventPermission ) ) { throw new IllegalArgumentException( WrapperManager.getRes().getString( "invalid permission: {0}", permission ) ); } if ( isReadOnly() ) { throw new SecurityException( WrapperManager.getRes().getString("Collection is read-only.") ); } m_permissions.add( permission ); } /** * Check and see if this set of permissions implies the permissions * expressed in "permission". * * @param permission The Permission object to compare * * @return True if "permission" is a proper subset of a permission in * the set, false if not. */ public boolean implies( Permission permission ) { if ( !( permission instanceof WrapperEventPermission ) ) { return false; } WrapperEventPermission wsp = (WrapperEventPermission)permission; int desiredMask = wsp.getActionMask(); int pendingMask = desiredMask; int foundMask = 0; for ( Enumeration en = m_permissions.elements(); en.hasMoreElements(); ) { WrapperEventPermission p2 = (WrapperEventPermission)en.nextElement(); if ( ( pendingMask & p2.getActionMask() ) != 0 ) { // This permission has one or more eventTypes that we need. if ( wsp.impliesIgnoreEventTypeMask( p2 ) ) { foundMask |= desiredMask & p2.getActionMask(); if ( foundMask == desiredMask ) { return true; } pendingMask = desiredMask ^ foundMask; } } } return false; } /** * Returns an enumeration of all the WrapperEventPermission * objects in the container. * * @return An enumeration of all the WrapperEventPermission * objects. */ public Enumeration elements() { return m_permissions.elements(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/security/WrapperPermission.java100644 0 0 10742 12440202301 26607 0ustar 0 0 package org.tanukisoftware.wrapper.security; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.security.BasicPermission; /** * WrapperPermissions are used to control access to the various methods of the * WrapperManager class. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Permission Target NameWhat the Permission AllowsRisks of Allowing this Permission
restartRestart the JVM * This is an extremely dangerous permission to grant. * Malicious applications can restart the JVM as a denial of service * attack. *
stopStop the JVM * This is an extremely dangerous permission to grant. * Malicious applications can stop the JVM as a denial of service * attack. *
stopImmediateStop the JVM immediately without running the shutdown hooks * This is an extremely dangerous permission to grant. * Malicious applications can stop the JVM as a denial of service * attack. *
signalStartingControl the starting timeouts. * Malicious code could set this to unrealistically small values as the application * is starting, thus causing startup failures. *
signalStoppingControl the stopping timeouts. * Malicious code could set this to unrealistically small values as the application * is stopping, thus causing the application to fail to shutdown cleanly. *
signalStoppedControl when the Wrapper is told that the Application has stopped. * Malicious code could call this before the application is actually stopped, * thus causing the application to fail to shutdown cleanly. *
logSends log output to the Wrapper over the back end socket at a specific log level. * Malicious code could send very large quanities of log output which could affect * the performance of the Wrapper. *
listServicesRequests the status of all services currently installed on the system. * Malicious code could use this information to find other weaknesses in the system. *
TODO: Complete javadocs. addWrapperEventListener service,core removeWrapperEventListener setConsoleTitle getUser getInteractiveUser getProperties getWrapperPID getJavaPID requestThreadDump test.appearHung test.accessViolation test.accessViolationNative * * @author Leif Mortenson */ public class WrapperPermission extends BasicPermission { /** * Serial Version UID. */ private static final long serialVersionUID = -4947853086614625658L; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperPermission with the specified name. * The name is the symbolic name of the WrapperPermission, such as "stop", * "restart", etc. An asterisk may appear at the end of the name, following * a ".", or by itself, to signify a wildcard match. * * @param name the name of the WrapperPermission. */ public WrapperPermission( String name ) { super( name ); } /** * Creates a new WrapperPermission with the specified name. * The name is the symbolic name of the WrapperPermission, such as "stop", * "restart", etc. An asterisk may appear at the end of the name, following * a ".", or by itself, to signify a wildcard match. * * @param name the name of the WrapperPermission. * @param actions The event type or event types to be registered. */ public WrapperPermission( String name, String actions ) { super( name, actions ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/security/WrapperServicePermission.java100644 0 0 42434 12440202301 30133 0ustar 0 0 package org.tanukisoftware.wrapper.security; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.security.Permission; import java.security.PermissionCollection; import java.util.Enumeration; import java.util.Vector; import java.util.StringTokenizer; import org.tanukisoftware.wrapper.WrapperManager; /** * WrapperServicePermissions are used to grant the right to start, stop, * pause, continue, interrogate, or send custom codes to other services * running on a Windows system. *

* These permissions are inherently quite dangerous so great care should be * taken when granting them. When doing so, try to only grant permission to * those services which really need to be controlled. *

* The following are examples of how to specify the permission within a policy * file. *

 *   grant codeBase "file:../lib/-" {
 *     // Grant various permissions to a specific service.
 *     permission org.tanukisoftware.wrapper.security.WrapperServicePermission "myservice", "interrogate";
 *     permission org.tanukisoftware.wrapper.security.WrapperServicePermission "myservice", "interrogate,start,stop";
 *     permission org.tanukisoftware.wrapper.security.WrapperServicePermission "myservice", "userCode";
 *     permission org.tanukisoftware.wrapper.security.WrapperServicePermission "myservice", "*";
 *
 *     // Grant various permissions to any service starting with "my".
 *     permission org.tanukisoftware.wrapper.security.WrapperServicePermission "my*", "*";
 *
 *     // Let the calling code do anything to any service on the system
 *     permission org.tanukisoftware.wrapper.security.WrapperServicePermission "*", "*";
 *     permission org.tanukisoftware.wrapper.security.WrapperServicePermission "*";
 *   };
 * 
*

* Possible actions include the following: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Permission Action NameWhat the Permission AllowsRisks of Allowing this Permission
startStart a service which is installed but has not been started.Malicious code could potentially start any service that is not currently running. * This includes services which were previously stopped or that are configured to be * started manually. Many Windows systems have several services stopped by default * because of the security hazards that they pose. Starting such services could open * the system up to attacks related to that service.
stopStop a service which is currently running.Malicious code could potentially stop running service. This could result in a * denial of service attack if the service is a web or database server. Or it * result in more dangerous attacks if the service is a firewall or virus scanner. *
pausePause a service which is currently running.Malicious code could potentially pause running service. This could result in a * denial of service attack if the service is a web or database server. Or it * result in more dangerous attacks if the service is a firewall or virus scanner. *
continueContinue a service which was previously paused.Malicious code could resume services which had been paused for a good reason.
interrogateInterrogate a service as to its current state.Malicious code learn a lot about a system and its weakness by probing which * services are currently running.
userCodeSend any custom user code to a service.The danger of this action depends on whether or not the service understands * custom user codes, and what it does with them. This could potentially be a * very dangerous permission to grant.
* * @author Leif Mortenson */ public class WrapperServicePermission extends Permission { /** * Serial Version UID. */ private static final long serialVersionUID = -6520453688353960444L; public static String ACTION_START = "start"; public static String ACTION_STOP = "stop"; public static String ACTION_PAUSE = "pause"; public static String ACTION_CONTINUE = "continue"; public static String ACTION_INTERROGATE = "interrogate"; public static String ACTION_USER_CODE = "userCode"; private static int MASK_START = 1; private static int MASK_STOP = 2; private static int MASK_PAUSE = 4; private static int MASK_CONTINUE = 8; private static int MASK_INTERROGATE = 16; private static int MASK_USER_CODE = 32; private static int MASK_ALL = MASK_START | MASK_STOP | MASK_PAUSE | MASK_CONTINUE | MASK_INTERROGATE | MASK_USER_CODE; private int m_actionMask; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperServicePermission for the specified service. * * @param serviceName The name of the service whose access is being * controlled. * @param actions The action or actions to be performed. */ public WrapperServicePermission( String serviceName, String actions ) { super( serviceName ); m_actionMask = buildActionMask( actions ); } /** * Creates a new WrapperServicePermission for the specified service. * This version of the constructor grants all actions. * * @param serviceName The name of the service whose access is being * controlled. */ public WrapperServicePermission( String serviceName ) { this( serviceName, "*" ); } /*--------------------------------------------------------------- * Permission Methods *-------------------------------------------------------------*/ /** * Checks two Permission objects for equality. *

* Do not use the equals method for making access control decisions; use * the implies method. * * @param obj The object we are testing for equality with this object. * * @return True if both Permission objects are equivalent. */ public boolean equals( Object obj ) { if ( obj == this ) { return true; } if ( !( obj instanceof WrapperServicePermission ) ) { return false; } WrapperServicePermission wsp = (WrapperServicePermission)obj; return ( m_actionMask == wsp.m_actionMask ) && getName().equals( wsp.getName() ); } /** * Return the canonical string representation of the actions. * Always returns present actions in the following order: * start, stop, pause, continue, interrogate. userCode. * * @return the canonical string representation of the actions. */ public String getActions() { StringBuffer sb = new StringBuffer(); boolean first = true; if ( ( m_actionMask & MASK_START ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( ACTION_START ); } if ( ( m_actionMask & MASK_STOP ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( ACTION_STOP ); } if ( ( m_actionMask & MASK_PAUSE ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( ACTION_CONTINUE ); } if ( ( m_actionMask & MASK_CONTINUE ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( ACTION_CONTINUE ); } if ( ( m_actionMask & MASK_INTERROGATE ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( ACTION_INTERROGATE ); } if ( ( m_actionMask & MASK_USER_CODE ) != 0 ) { if ( first ) { sb.append( ',' ); } else { first = false; } sb.append( ACTION_USER_CODE ); } return sb.toString(); } /** * Checks if this WrapperServicePermission object "implies" the * specified permission. *

* More specifically, this method returns true if:

*

    *
  • p2 is an instanceof FilePermission,

    *

  • p2's actions are a proper subset of this object's actions, * and

    *

  • p2's service name is implied by this object's service name. * For example, "MyApp*" implies "MyApp". *
* * @param p2 The permission to check against. * * @return True if the specified permission is implied by this object. */ public boolean implies( Permission p2 ) { if ( !( p2 instanceof WrapperServicePermission ) ) { return false; } WrapperServicePermission wsp = (WrapperServicePermission)p2; // we get the effective mask. i.e., the "and" of this and that. // They must be equal to that.mask for implies to return true. return ( ( m_actionMask & wsp.m_actionMask ) == wsp.m_actionMask ) && impliesIgnoreActionMask( wsp ); } /** * Returns a custom WSCollection implementation of a PermissionCollection. * * @return A custom WSCollection implementation of a PermissionCollection. */ public PermissionCollection newPermissionCollection() { return new WSCollection(); } /** * Returns the hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { return getName().hashCode(); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Returns the action mask of the Permission. * * @return The action mask of the Permission. */ int getActionMask() { return m_actionMask; } /** * Tests whether this permissions implies another without taking the * action mask into account. * * @param p2 The permission to check against. * * @return True if the specified permission is implied by this object. */ boolean impliesIgnoreActionMask( WrapperServicePermission p2 ) { if ( getName().equals( p2.getName() ) ) { return true; } if ( p2.getName().endsWith( "*" ) ) { if ( getName().startsWith( p2.getName().substring( 0, p2.getName().length() - 1 ) ) ) { return true; } } return false; } /** * Builds an action mask given a comma separated list of actions. * * @param actions The list of actions. * * @return The action mask. */ private int buildActionMask( String actions ) { // Check for the constants first as they are used internally. if ( actions == ACTION_START ) { return MASK_START; } else if ( actions == ACTION_STOP ) { return MASK_STOP; } else if ( actions == ACTION_PAUSE ) { return MASK_PAUSE; } else if ( actions == ACTION_CONTINUE ) { return MASK_CONTINUE; } else if ( actions == ACTION_INTERROGATE ) { return MASK_INTERROGATE; } else if ( actions == ACTION_USER_CODE ) { return MASK_USER_CODE; } else if ( actions.equals( "*" ) ) { return MASK_ALL; } int mask = 0; StringTokenizer st = new StringTokenizer( actions, "," ); while ( st.hasMoreTokens() ) { String action = st.nextToken(); if ( action.equals( ACTION_START ) ) { mask |= MASK_START; } else if ( action.equals( ACTION_STOP ) ) { mask |= MASK_STOP; } else if ( action.equals( ACTION_PAUSE ) ) { mask |= MASK_PAUSE; } else if ( action.equals( ACTION_CONTINUE ) ) { mask |= MASK_CONTINUE; } else if ( action.equals( ACTION_INTERROGATE ) ) { mask |= MASK_INTERROGATE; } else if ( action.equals( ACTION_USER_CODE ) ) { mask |= MASK_USER_CODE; } else { throw new IllegalArgumentException( WrapperManager.getRes().getString( "Invalid permission action: \"{0}\"" , action ) ); } } return mask; } } final class WSCollection extends PermissionCollection { /** * Serial Version UID. */ private static final long serialVersionUID = 7056999828486119722L; private Vector m_permissions = new Vector(); /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates an empty WSCollection. */ public WSCollection() { } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Adds a permission to the FilePermissions. The key for the hash is * permission.path. * * @param permission the Permission object to add. * * @exception IllegalArgumentException If the permission is not a * FilePermission * * @exception SecurityException If this FilePermissionCollection object * has been marked readonly */ public void add( Permission permission ) { if ( !( permission instanceof WrapperServicePermission ) ) { throw new IllegalArgumentException(WrapperManager.getRes().getString( "invalid permission: {0}", permission ) ); } if ( isReadOnly() ) { throw new SecurityException( WrapperManager.getRes().getString("Collection is read-only." ) ); } m_permissions.add( permission ); } /** * Check and see if this set of permissions implies the permissions * expressed in "permission". * * @param permission The Permission object to compare * * @return True if "permission" is a proper subset of a permission in * the set, false if not. */ public boolean implies( Permission permission ) { if ( !( permission instanceof WrapperServicePermission ) ) { return false; } WrapperServicePermission wsp = (WrapperServicePermission)permission; int desiredMask = wsp.getActionMask(); int pendingMask = desiredMask; int foundMask = 0; for ( Enumeration en = m_permissions.elements(); en.hasMoreElements(); ) { WrapperServicePermission p2 = (WrapperServicePermission)en.nextElement(); if ( ( pendingMask & p2.getActionMask() ) != 0 ) { // This permission has one or more actions that we need. if ( wsp.impliesIgnoreActionMask( p2 ) ) { foundMask |= desiredMask & p2.getActionMask(); if ( foundMask == desiredMask ) { return true; } pendingMask = desiredMask ^ foundMask; } } } return false; } /** * Returns an enumeration of all the WrapperServicePermission * objects in the container. * * @return An enumeration of all the WrapperServicePermission * objects. */ public Enumeration elements() { return m_permissions.elements(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/security/WrapperUserEventPermission.java100644 0 0 25103 12440202301 30445 0ustar 0 0 package org.tanukisoftware.wrapper.security; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.security.AccessControlException; import java.security.BasicPermission; import java.security.Permission; import java.util.ArrayList; import java.util.StringTokenizer; import org.tanukisoftware.wrapper.WrapperManager; /** * WrapperEventPermissions are used to grant the right to register to start * receiving events from the Wrapper. *

* Some of these permissions can result in performance degredations if used * impropperly. *

* The following are examples of how to specify the permission within a policy * file. * *

 *   grant codeBase "file:../lib/-" {
 *     // Grant various permissions to a specific service.
 *     permission org.tanukisoftware.wrapper.security.WrapperEventPermission "service";
 *     permission org.tanukisoftware.wrapper.security.WrapperEventPermission "service, core";
 *     permission org.tanukisoftware.wrapper.security.WrapperEventPermission "*";
 *   };
 * 
*

* Possible eventTypes include the following: * * * * * * * * * * * * * * * * * * * * * * * * *
Permission Event Type NameWhat the Permission AllowsRisks of Allowing this Permission
serviceRegister to obtain events whenever the Wrapper service receives any * service events.Malicious code could receive this event and never return and thus cause * performance and timeout problems with the Wrapper. Normal use of these events * are quite safe however.
controlRegister to obtain events whenever the Wrapper receives any system * control signals.Malicious code could trap and consome control events, thus preventing an * application from being shut down cleanly.
coreRegister to obtain events on the core workings of the Wrapper.Malicious code or even well meaning code can greatly affect the * performance of the Wrapper simply by handling these methods slowly. Some of * these events are fired from within the core timing code of the Wrapper. They * are useful for testing and performance checks, but in general they should not * be used by most applications.
* * @author Leif Mortenson */ public final class WrapperUserEventPermission extends BasicPermission { /** * Serial Version UID. */ private static final long serialVersionUID = 8916489326587298168L; private final int EVENT_MIN = 1; private final int EVENT_MAX = 32767; private ArrayList m_eventArr; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new WrapperEventPermission for the specified service. * * @param action The event type or event types to be registered. */ public WrapperUserEventPermission( String action ) { super( "fireUserEvent", String.valueOf( action ) ); parseValids( action ); } /** * Creates a new WrapperEventPermission for the specified service. * * @param name Name of the event. * @param action The event type or event types to be registered. */ public WrapperUserEventPermission( String name, String action ) { super( name, action ); parseValids( action ); } /** * Return the canonical string representation of the eventTypes. * Always returns present eventTypes in the following order: * start, stop, pause, continue, interrogate. userCode. * * @return The canonical string representation of the eventTypes. */ public String getActions() { String s = ""; for ( int i = 0; i < m_eventArr.size(); i++ ) { if ( i > 0 ) { s = s.concat( "," ); } s = s.concat( (String)m_eventArr.get( i ) ); } return s; } /** * Checks if this WrapperEventPermission object "implies" the * specified permission. *

* More specifically, this method returns true if:

*

    *
  • p2 is an instanceof FilePermission,

    *

  • p2's eventTypes are a proper subset of this object's eventTypes, * and

    *

  • p2's service name is implied by this object's service name. * For example, "MyApp*" implies "MyApp". *
* * @param p2 the permission to check against. * * @return True if the specified permission is implied by this object. */ public boolean implies( Permission p2 ) { int current, min, max, check, border; String element; check = Integer.parseInt( p2.getActions() ); for ( int i = 0; i < m_eventArr.size(); i++ ) { element = (String)m_eventArr.get( i ); border = element.indexOf( '-' ); if ( border >= 0 ) { min = Integer.parseInt( element.substring( 0, border ) ); max = Integer.parseInt( element.substring( border + 1 ) ); if ( min <= check && check <= max ) { return true; } } else { current = Integer.parseInt( element ); if ( current == check ) { return true; } } } return false; } /** * This method evaluates the passed in permission's action String and stores them in * chunks in an array * * @param action the permission's actions */ private void parseValids( String action ) { int lastValue = 0, currentValue; m_eventArr = new ArrayList(); if ( action.compareTo( "*" ) == 0 ) { m_eventArr.add( new String( EVENT_MIN + "-" + EVENT_MAX ) ); return; } StringTokenizer strok = new StringTokenizer( action.trim(), "," ); while ( strok.hasMoreTokens() ) { String element = strok.nextToken(); if ( element.indexOf( '*' ) >= 0 ) { throw new AccessControlException( WrapperManager.getRes().getString( "can''t define ''*'' inside a sequence." ) ); } int range = element.indexOf( "-" ); if ( range >= 0 ) { if ( range == 0 ) { if ( m_eventArr.size() != 0 ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} has to be first element in sequence.", element ) ); } else { lastValue = Integer.parseInt( element.substring( 1 ) ); if ( lastValue <= EVENT_MIN || lastValue > EVENT_MAX ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} is out of bounds.", new Integer( lastValue ) ) ); } m_eventArr.add( new String( EVENT_MIN + "-" + lastValue ) ); } } else if ( range == element.length() - 1 ) { currentValue = Integer.parseInt( element.substring( 0, element.length() - 1 ) ); if ( currentValue <= EVENT_MIN || currentValue > EVENT_MAX ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} is out of bounds.", new Integer( lastValue ) ) ); } if ( currentValue < lastValue ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} is not sorted.", new Integer( currentValue ) ) ); } lastValue = currentValue; if ( strok.hasMoreTokens() ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} has to be last element in sequence.", element ) ); } m_eventArr.add( currentValue + "-" + EVENT_MAX ); } else { currentValue = Integer.parseInt( element.substring( 0, range ) ); if ( currentValue <= EVENT_MIN || currentValue > EVENT_MAX ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} is out of bounds.", new Integer( lastValue ) ) ); } if ( currentValue < lastValue ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} is not sorted.", new Integer( currentValue ) ) ); } lastValue = currentValue; currentValue = Integer.parseInt( element.substring( range + 1 ) ); if ( currentValue <= EVENT_MIN || currentValue > EVENT_MAX ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} is out of bounds.", new Integer( lastValue ) ) ); } if ( currentValue < lastValue ) { throw new AccessControlException( WrapperManager.getRes().getString( "Value {0} is not sorted.", new Integer( currentValue ) ) ); } m_eventArr.add( lastValue + "-" + currentValue ); lastValue = currentValue; } } else { currentValue = Integer.parseInt( element ); if ( currentValue < lastValue ) { throw new java.security.AccessControlException( WrapperManager.getRes().getString( "Value {0} is not sorted.", new Integer( currentValue ) ) ); } lastValue = currentValue; m_eventArr.add( element ); } } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test2/Jar2Main.java100644 0 0 1656 12440202301 23677 0ustar 0 0 package org.tanukisoftware.wrapper.test2; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.test.JarMain; /** * * * @author Leif Mortenson */ public class Jar2Main { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { System.out.println( "Calling JarMain.main." ); JarMain.main( args ); System.out.println( "Returned from JarMain.main." ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/AbstractActionApp.java100644 0 0 74614 12440202301 25600 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.util.Enumeration; import java.util.Properties; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperProcess; import org.tanukisoftware.wrapper.WrapperProcessConfig; import org.tanukisoftware.wrapper.WrapperServiceException; import org.tanukisoftware.wrapper.WrapperWin32Service; import org.tanukisoftware.wrapper.event.WrapperControlEvent; import org.tanukisoftware.wrapper.event.WrapperEvent; import org.tanukisoftware.wrapper.event.WrapperEventListener; /** * @author Leif Mortenson */ public abstract class AbstractActionApp implements WrapperEventListener { private static String c_encoding; private DeadlockPrintStream m_out; private DeadlockPrintStream m_err; private Thread m_runner; private Thread m_consoleRunner; private boolean m_ignoreControlEvents; private boolean m_users; private boolean m_groups; private boolean m_nestedExit; private long m_eventMask = 0xffffffffffffffffL; private int m_slowSeconds = 0; private String m_serviceName = "testWrapper"; private String m_consoleTitle = "Java Service Wrapper"; private String m_childCommand = "ls"; private boolean m_childDetached = true; /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ static { // In order to read the output from some processes correctly we need to get the correct encoding. // On some systems, the underlying system encoding is different than the file encoding. c_encoding = System.getProperty( "sun.jnu.encoding" ); if ( c_encoding == null ) { c_encoding = System.getProperty( "file.encoding" ); if ( c_encoding == null ) { // Default to Latin1 c_encoding = "Cp1252"; } } } /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ protected AbstractActionApp() { m_runner = new Thread( Main.getRes().getString( "WrapperActionTest_Runner" ) ) { public void run() { while ( true ) { if ( m_users ) { System.out.println( Main.getRes().getString( "The current user is: {0}", WrapperManager.getUser( m_groups ) ) ); System.out.println( Main.getRes().getString( "The current interactive user is: {0}" , WrapperManager.getInteractiveUser( m_groups ) ) ); } synchronized( AbstractActionApp.class ) { try { AbstractActionApp.class.wait( 5000 ); } catch ( InterruptedException e ) { } } } } }; m_runner.setDaemon( true ); m_runner.start(); } /*--------------------------------------------------------------- * WrapperEventListener Methods *-------------------------------------------------------------*/ /** * Called whenever a WrapperEvent is fired. The exact set of events that a * listener will receive will depend on the mask supplied when * WrapperManager.addWrapperEventListener was called to register the * listener. * * Listener implementations should never assume that they will only receive * events of a particular type. To assure that events added to future * versions of the Wrapper do not cause problems with user code, events * should always be tested with "if ( event instanceof {EventClass} )" * before casting it to a specific event type. * * @param event WrapperEvent which was fired. */ public void fired( WrapperEvent event ) { System.out.println( Main.getRes().getString( "Received event: {0}", event ) ); if ( event instanceof WrapperControlEvent ) { System.out.println( Main.getRes().getString( " Consume and ignore." ) ); ((WrapperControlEvent)event).consume(); } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ protected boolean ignoreControlEvents() { return m_ignoreControlEvents; } protected boolean isNestedExit() { return m_nestedExit; } protected void setEventMask( long eventMask ) { m_eventMask = eventMask; } protected void setSlowSeconds( int slowSeconds ) { m_slowSeconds = slowSeconds; } protected void setServiceName( String serviceName ) { m_serviceName = serviceName; } protected void setConsoleTitle( String consoleTitle ) { m_consoleTitle = consoleTitle; } protected void setChildParams( String childCommand, boolean childDetached ) { m_childCommand = childCommand; m_childDetached = childDetached; } protected void prepareSystemOutErr() { m_out = new DeadlockPrintStream( System.out ); System.setOut( m_out ); m_err = new DeadlockPrintStream( System.err ); System.setErr( m_err ); } protected boolean doAction( String action ) { if ( action.equals( "stop0" ) ) { WrapperManager.stop( 0 ); } else if ( action.equals( "stop1" ) ) { WrapperManager.stop( 1 ); } else if ( action.equals( "exit0" ) ) { System.exit( 0 ); } else if ( action.equals( "exit1" ) ) { System.exit( 1 ); } else if ( action.equals( "nestedexit1" ) ) { m_nestedExit = true; WrapperManager.stop( 1 ); } else if ( action.equals( "stopimmediate0" ) ) { WrapperManager.stopImmediate( 0 ); } else if ( action.equals( "stopimmediate1" ) ) { WrapperManager.stopImmediate( 1 ); } else if ( action.equals( "stopandreturn0" ) ) { WrapperManager.stopAndReturn( 0 ); } else if ( action.equals( "halt0" ) ) { Runtime.getRuntime().halt( 0 ); } else if ( action.equals( "halt1" ) ) { Runtime.getRuntime().halt( 1 ); } else if ( action.equals( "restart" ) ) { WrapperManager.restart(); } else if ( action.equals( "restartandreturn" ) ) { WrapperManager.restartAndReturn(); } else if ( action.equals( "access_violation" ) ) { // The bug we used to cause this is not in most modern VMs so this is not shown by default. WrapperManager.accessViolation(); } else if ( action.equals( "access_violation_native" ) ) { WrapperManager.accessViolationNative(); } else if ( action.equals( "appear_hung" ) ) { WrapperManager.appearHung(); } else if ( action.equals( "appear_slow" ) ) { WrapperManager.appearSlow( m_slowSeconds ); } else if ( action.equals( "appear_slow_1" ) ) { WrapperManager.appearSlow( 1 ); } else if ( action.equals( "appear_slow_5" ) ) { WrapperManager.appearSlow( 5 ); } else if ( action.equals( "appear_slow_reset" ) ) { WrapperManager.appearSlow( 0 ); } else if ( action.equals( "deadlock" ) ) { if ( WrapperManager.isStandardEdition() ) { System.out.println( Main.getRes().getString( "Creating a 2-object deadlock...") ); DeadLockBase.create2ObjectDeadlock( false, false ); } else { System.out.println( Main.getRes().getString( "Deadlock checks require the Standard Edition.") ); } } else if ( action.equals( "outofmemory" ) ) { throw new OutOfMemoryError(); } else if ( action.equals( "ignore_events" ) ) { m_ignoreControlEvents = true; } else if ( action.equals( "dump" ) ) { WrapperManager.requestThreadDump(); } else if ( action.equals( "deadlock_out" ) ) { System.out.println( Main.getRes().getString( "Deadlocking System.out and System.err ..." ) ); m_out.setDeadlock( true ); m_err.setDeadlock( true ); } else if ( action.equals( "users" ) ) { if ( !m_users ) { System.out.println( Main.getRes().getString( "Begin polling the current and interactive users." ) ); m_users = true; } else if ( m_groups ) { System.out.println( Main.getRes().getString("Stop polling for group info." ) ); m_groups = false; } else { System.out.println( Main.getRes().getString("Stop polling the current and interactive users." ) ); m_users = false; } synchronized( AbstractActionApp.class ) { AbstractActionApp.class.notifyAll(); } } else if ( action.equals( "groups" ) ) { if ( ( !m_users ) || ( !m_groups ) ) { System.out.println( Main.getRes().getString( "Begin polling the current and interactive users with group info." ) ); m_users = true; m_groups = true; } else { System.out.println( Main.getRes().getString( "Stop polling for group info." ) ); m_groups = false; } synchronized( AbstractActionApp.class ) { AbstractActionApp.class.notifyAll(); } } else if ( action.equals( "console" ) ) { if ( m_consoleRunner == null ) { m_consoleRunner = new Thread( "console-runner" ) { public void run() { System.out.println(); System.out.println( Main.getRes().getString( "Start prompting for actions." ) ); try { BufferedReader r = new BufferedReader(new InputStreamReader(System.in)); String line; try { do { System.out.println( Main.getRes().getString( "Input an action ('help' for a list of actions):") ); line = r.readLine(); if ((line != null) && (!line.equals(""))) { System.out.println(Main.getRes().getString( "Read action: {0}", line ) ); if ( !doAction( line ) ) { if ( !line.equals( "help" ) ) { System.out.println( Main.getRes().getString( "Unknown action: {0}", line ) ); } printActions(); } } else { System.out.println(Main.getRes().getString( "Read action: " ) ); } } while (true); } catch ( IOException e ) { e.printStackTrace(); } } finally { System.out.println( Main.getRes().getString( "Stop prompting for actions." ) ); System.out.println(); m_consoleRunner = null; } } }; m_consoleRunner.setDaemon( true ); m_consoleRunner.start(); } } else if ( action.equals( "idle" ) ) { System.out.println( Main.getRes().getString( "Run idle." ) ); m_users = false; m_groups = false; synchronized( AbstractActionApp.class ) { AbstractActionApp.class.notifyAll(); } } else if ( action.equals( "properties" ) ) { System.out.println( Main.getRes().getString( "Dump System Properties:" ) ); Properties props = System.getProperties(); for ( Enumeration en = props.propertyNames(); en.hasMoreElements(); ) { String name = (String)en.nextElement(); System.out.println( " " + name + "=" + props.getProperty( name ) ); } System.out.println(); } else if ( action.equals( "configuration" ) ) { System.out.println( Main.getRes().getString( "Dump Wrapper Properties:" ) ); Properties props = WrapperManager.getProperties(); for ( Enumeration en = props.propertyNames(); en.hasMoreElements(); ) { String name = (String)en.nextElement(); System.out.println( " " + name + "=" + props.getProperty( name ) ); } System.out.println(); } else if ( action.equals( "listener" ) ) { System.out.println( Main.getRes().getString( "Updating Event Listeners:" ) ); WrapperManager.removeWrapperEventListener( this ); WrapperManager.addWrapperEventListener( this, m_eventMask ); } else if ( action.equals( "service_list" ) ) { /* for ( int i = 0; i < 1000; i++ ) { WrapperWin32Service[] services = WrapperManager.listServices(); } */ WrapperWin32Service[] services = WrapperManager.listServices(); if ( services == null ) { System.out.println( Main.getRes().getString( "Services not supported by current platform." ) ); } else { System.out.println( Main.getRes().getString( "Registered Services:" ) ); for ( int i = 0; i < services.length; i++ ) { System.out.println( " " + services[i] ); } } } else if ( action.equals( "service_interrogate" ) ) { try { /* for ( int i = 0; i < 10000; i++ ) { WrapperWin32Service service = WrapperManager.sendServiceControlCode( m_serviceName, WrapperManager.SERVICE_CONTROL_CODE_INTERROGATE ); } */ WrapperWin32Service service = WrapperManager.sendServiceControlCode( m_serviceName, WrapperManager.SERVICE_CONTROL_CODE_INTERROGATE ); System.out.println( Main.getRes().getString( "Service after interrogate: {0}", service ) ); } catch ( WrapperServiceException e ) { e.printStackTrace(); } } else if ( action.equals( "service_start" ) ) { try { WrapperWin32Service service = WrapperManager.sendServiceControlCode( m_serviceName, WrapperManager.SERVICE_CONTROL_CODE_START ); System.out.println( Main.getRes().getString( "Service after start: {0}", service ) ); } catch ( WrapperServiceException e ) { e.printStackTrace(); } } else if ( action.equals( "service_stop" ) ) { try { WrapperWin32Service service = WrapperManager.sendServiceControlCode( m_serviceName, WrapperManager.SERVICE_CONTROL_CODE_STOP ); System.out.println( Main.getRes().getString( "Service after stop: {0}", service ) ); } catch ( WrapperServiceException e ) { e.printStackTrace(); } } else if ( action.equals( "service_user" ) ) { try { for ( int i = 128; i < 256; i+=10 ) { WrapperWin32Service service = WrapperManager.sendServiceControlCode( m_serviceName, i ); System.out.println( Main.getRes().getString( "Service after user code {0} : {1}", new Integer( i ), service ) ); } } catch ( WrapperServiceException e ) { e.printStackTrace(); } } else if ( action.equals( "console_title" ) ) { if ( !WrapperManager.isWindows() ) { System.out.println( Main.getRes().getString( "Setting the console title not supported on UNIX platforms." ) ); // The call is fine but it doesn't do anything. } WrapperManager.setConsoleTitle( m_consoleTitle ); } else if ( action.equals( "child_exec" ) ) { // This command is really meant only to be used by the GUI but can also be called from the console if known. doExec( m_childCommand, m_childDetached ); } else if ( action.equals( "gc" ) ) { System.out.println( Main.getRes().getString( "Begin GC..." ) ); System.gc(); System.out.println( Main.getRes().getString( "GC complete." ) ); } else if ( action.equals( "is_professional" ) ) { System.out.println( Main.getRes().getString( "Professional Edition: " ) + WrapperManager.isProfessionalEdition() ); } else if ( action.equals( "is_standard" ) ) { System.out.println( Main.getRes().getString( "Standard Edition: " ) + WrapperManager.isStandardEdition() ); } else if ( action.startsWith( "exec " ) && ( action.length() > 5 ) ) { String command = action.substring( 5 ); doExec( command, false ); } else if ( action.startsWith( "exec_detached " ) && ( action.length() > 14 ) ) { String command = action.substring( 14 ); doExec( command, true ); } else { // Unknown action return false; } return true; } private static Thread handleInputStream( final InputStream is, final String encoding, String pid, String pipeName ) { final String label = Main.getRes().getString( " Process #{0} {1}", pid, pipeName ); Thread runner = new Thread( "exec_runner_" + pipeName + "_" + pid ) { public void run() { BufferedReader br; String line; try { br = new BufferedReader( new InputStreamReader( is, encoding ) ); try { while ( ( line = br.readLine() ) != null ) { System.out.println( label + ": " + line ); } } finally { br.close(); } } catch ( IOException e ) { e.printStackTrace(); } } }; runner.start(); return runner; } private void doExec( String command, boolean detached ) { try { WrapperProcessConfig processConfig = new WrapperProcessConfig(); processConfig.setDetached( detached ); String type; if ( command.startsWith( "FORK_EXEC " ) ) { processConfig.setStartType( WrapperProcessConfig.FORK_EXEC ); type = "FORK_EXEC"; command.substring( 10 ); } else if ( command.startsWith( "POSIX_SPAWN " ) ) { processConfig.setStartType( WrapperProcessConfig.POSIX_SPAWN ); type = "POSIX_SPAWN"; command.substring( 12 ); } else if ( command.startsWith( "VFORK_EXEC " ) ) { processConfig.setStartType( WrapperProcessConfig.VFORK_EXEC ); type = "VFORK_EXEC"; command.substring( 11 ); } else if ( command.startsWith( "DYNAMIC " ) ) { processConfig.setStartType( WrapperProcessConfig.DYNAMIC ); type = "DYNAMIC"; command.substring( 8 ); } else { type = "DYNAMIC"; } if ( detached ) { System.out.println( Main.getRes().getString( "Execute Detached Child Process with type {0}: {1}", type, command ) ); } else { System.out.println( Main.getRes().getString( "Execute Managed Child Process: with type {0}: {1}", type, command ) ); } final WrapperProcess process = WrapperManager.exec( command, processConfig ); final String pid = Integer.toString( process.getPID() ); System.out.println( Main.getRes().getString( " Process #{0} launched.", pid ) ); final Thread outRunner = handleInputStream( process.getInputStream(), c_encoding, pid, "stdout" ); final Thread errRunner = handleInputStream( process.getErrorStream(), c_encoding, pid, "stderr" ); Thread runner = new Thread( "exec_runner_process_" + pid ) { public void run() { try { // Wait for the stdout and stderr reader threads to complete before we say the process completed to avoid confusion. outRunner.join(); errRunner.join(); System.out.println( Main.getRes().getString( " Process #{0} terminated with exitCode={1}", pid, Integer.toString( process.waitFor() ) ) ); } catch ( Throwable t ) { System.out.println( Main.getRes().getString( " Process #{0} unexpected error: {1} ", pid, t.getMessage() ) ); t.printStackTrace(); } } }; runner.start(); } catch ( Throwable t ) { System.out.println( Main.getRes().getString( "Failed to launch child process: {0}", t.getMessage() ) ); t.printStackTrace(); } } /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ protected static void printActions() { System.err.println( "" ); System.err.println( Main.getRes().getString( "[ACTIONS]" ) ); System.err.println( Main.getRes().getString( " help : Shows this help message" ) ); System.err.println( Main.getRes().getString( " Actions which should cause the Wrapper to exit cleanly:" ) ); System.err.println( Main.getRes().getString( " stop0 : Calls WrapperManager.stop(0)" ) ); System.err.println( Main.getRes().getString( " exit0 : Calls System.exit(0)" ) ); System.err.println( Main.getRes().getString( " stopimmediate0 : Calls WrapperManager.stopImmediate(0)" ) ); System.err.println( Main.getRes().getString( " stopandreturn0 : Calls WrapperManager.stopAndReturn(0)" ) ); System.err.println( Main.getRes().getString( " Actions which should cause the Wrapper to exit in an error state:" ) ); System.err.println( Main.getRes().getString( " stop1 : Calls WrapperManager.stop(1)" ) ); System.err.println( Main.getRes().getString( " exit1 : Calls System.exit(1)" ) ); System.err.println( Main.getRes().getString( " nestedexit1 : Calls System.exit(1) within WrapperListener.stop(1) callback" ) ); System.err.println( Main.getRes().getString( " stopimmediate1 : Calls WrapperManager.stopImmediate(1)" ) ); System.err.println( Main.getRes().getString( " Actions which should cause the Wrapper to restart the JVM:" ) ); System.err.println( Main.getRes().getString( " access_violation_native : Calls WrapperManager.accessViolationNative()" ) ); System.err.println( Main.getRes().getString( " appear_hung : Calls WrapperManager.appearHung()" ) ); System.err.println( Main.getRes().getString( " halt0 : Calls Runtime.getRuntime().halt(0)" ) ); System.err.println( Main.getRes().getString( " halt1 : Calls Runtime.getRuntime().halt(1)" ) ); System.err.println( Main.getRes().getString( " restart : Calls WrapperManager.restart()" ) ); System.err.println( Main.getRes().getString( " restartandreturn : Calls WrapperManager.restartAndReturn()" ) ); System.err.println( Main.getRes().getString( " Additional Tests:" ) ); System.err.println( Main.getRes().getString( " appear_slow_1 : Calls WrapperManager.appearSlow(1)" ) ); System.err.println( Main.getRes().getString( " appear_slow_5 : Calls WrapperManager.appearSlow(5)" ) ); System.err.println( Main.getRes().getString( " appear_slow_reset : Calls WrapperManager.appearSlow(0) to return to normal" ) ); System.err.println( Main.getRes().getString( " deadlock : Executes some deadlocking code to test deadlock detection" ) ); System.err.println( Main.getRes().getString( " outofmemory : Simulates an OutOfMemoryError being thrown" ) ); System.err.println( Main.getRes().getString( " ignore_events : Makes this application ignore control events." ) ); System.err.println( Main.getRes().getString( " dump : Calls WrapperManager.requestThreadDump()" ) ); System.err.println( Main.getRes().getString( " deadlock_out : Deadlocks the JVM's System.out and err streams." ) ); System.err.println( Main.getRes().getString( " users : Start polling the current and interactive users." ) ); System.err.println( Main.getRes().getString( " groups : Start polling the current and interactive users with groups." ) ); System.err.println( Main.getRes().getString( " console : Prompt for actions in the console." ) ); System.err.println( Main.getRes().getString( " idle : Do nothing just run in idle mode." ) ); System.err.println( Main.getRes().getString( " properties : Dump all System Properties to the console." ) ); System.err.println( Main.getRes().getString( " configuration : Dump all Wrapper Configuration Properties to the console." ) ); System.err.println( Main.getRes().getString( " gc : Perform a GC sweep." ) ); System.err.println( Main.getRes().getString( " is_professional : Displays whether or not this is a Professional Edition Wrapper." ) ); System.err.println( Main.getRes().getString( " is_standard : Displays whether or not this is at least a Standard Edition Wrapper." ) ); if ( WrapperManager.isProfessionalEdition() ) { System.err.println( Main.getRes().getString( " exec : Executes a managed child process." ) ); System.err.println( Main.getRes().getString( " exec_detached : Executes a detached child process." ) ); } System.err.println( "" ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/BackgroundThreads.java100644 0 0 6035 12440202301 25600 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * * * @author Leif Mortenson */ public class BackgroundThreads implements Runnable { private static boolean m_started = false; /*--------------------------------------------------------------- * Runnable Method *-------------------------------------------------------------*/ public void run() { m_started = true; while(true) { System.out.println(Main.getRes().getString( "{0} running", Thread.currentThread().getName() ) ); try { Thread.sleep(500); } catch (InterruptedException e) { } } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println(Main.getRes().getString( "Background Thread Test Running..." ) ); System.out.println(Main.getRes().getString( "Launching background non-daemon threads...") ); BackgroundThreads app = new BackgroundThreads(); for (int i = 0; i < 2; i++) { Thread thread = new Thread(app, "App-Thread-" + i); thread.start(); } // Wait for at least one of the daemon threads to start to make sure // this main method does not exit prematurely and trigger a JVM // shutdown. while ( !m_started ) { try { Thread.sleep( 10 ); } catch ( InterruptedException e ) { // Ignore. } } System.out.println( Main.getRes().getString( "The JVM should now continue to run indefinitely.") ); System.out.println(Main.getRes().getString( "Background Thread Test Main Done..." ) ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/ChildWrapper.java100644 0 0 14463 12440202301 24616 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperJNIError; import org.tanukisoftware.wrapper.WrapperLicenseError; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperProcess; import org.tanukisoftware.wrapper.WrapperProcessConfig; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.Random; /** * * * @author Leif Mortenson */ public class ChildWrapper { private static String c_encoding; /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ static { // In order to read the output from some processes correctly we need to get the correct encoding. // On some systems, the underlying system encoding is different than the file encoding. c_encoding = System.getProperty( "sun.jnu.encoding" ); if ( c_encoding == null ) { c_encoding = System.getProperty( "file.encoding" ); if ( c_encoding == null ) { // Default to Latin1 c_encoding = "Cp1252"; } } } private static void handleJavaProcess( String command ) throws IOException, InterruptedException { Process process = Runtime.getRuntime().exec( command ); try { BufferedReader br; String line; // Dump all stdout br = new BufferedReader( new InputStreamReader( process.getInputStream(), c_encoding ) ); try { while ( ( line = br.readLine() ) != null ) { System.out.println( "stdout: " + line ); } } finally { br.close(); } // Dump all stderr br = new BufferedReader( new InputStreamReader( process.getErrorStream(), c_encoding ) ); try { while ( ( line = br.readLine() ) != null ) { System.out.println( "stderr: " + line ); } } finally { br.close(); } } finally { int exitCode = process.waitFor(); System.out.println( "exitCode: " + exitCode ); } } private static void handleWrapperProcess( String command ) throws IOException, InterruptedException { WrapperProcess process = WrapperManager.exec( command ); try { BufferedReader br; String line; // Dump all stdout br = new BufferedReader( new InputStreamReader( process.getInputStream(), c_encoding ) ); try { while ( ( line = br.readLine() ) != null ) { System.out.println( "stdout: " + line ); } } finally { br.close(); } // Dump all stderr br = new BufferedReader( new InputStreamReader( process.getErrorStream(), c_encoding ) ); try { while ( ( line = br.readLine() ) != null ) { System.out.println( "stderr: " + line ); } } finally { br.close(); } } finally { int exitCode = process.waitFor(); System.out.println( "exitCode: " + exitCode ); } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { System.out.println( "Communicate with child processes using encoding: " + c_encoding ); try { String wrapperCmdVersion; String wrapperCmdTestWrapper; if ( WrapperManager.isWindows() ) { wrapperCmdVersion = "..\\bin\\wrapper.exe -v"; wrapperCmdTestWrapper = "..\\bin\\wrapper.exe -c ..\\conf\\wrapper.conf -- exit0"; } else { wrapperCmdVersion = "../bin/wrapper -v"; wrapperCmdTestWrapper = "../bin/wrapper -c ../conf/wrapper.conf -- exit0"; } String batCmd = "cmd /c ..\\bin\\TestWrapper.bat exit0"; String batDirect = "..\\bin\\TestWrapper.bat exit0"; System.out.println( Main.getRes().getString( "Runtime.exec test (Version)." ) ); handleJavaProcess( wrapperCmdVersion ); System.out.println( Main.getRes().getString( "Runtime.exec test (TestWrapper)." ) ); handleJavaProcess( wrapperCmdTestWrapper ); if ( WrapperManager.isStandardEdition() ) { System.out.println( Main.getRes().getString( "WrapperManager.exec test (Version)." ) ); handleWrapperProcess( wrapperCmdVersion ); System.out.println( Main.getRes().getString( "WrapperManager.exec test (TestWrapper)." ) ); handleWrapperProcess( wrapperCmdTestWrapper ); } if ( WrapperManager.isWindows() ) { System.out.println( Main.getRes().getString( "Runtime.exec test (Bat with cmd)." ) ); handleJavaProcess( batCmd ); System.out.println( Main.getRes().getString( "Runtime.exec test (Bat direct)." ) ); handleJavaProcess( batDirect ); } } catch ( Exception e ) { e.printStackTrace(); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/DaemonThreads.java100644 0 0 6035 12440202301 24724 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * * * @author Leif Mortenson */ public class DaemonThreads implements Runnable { private static boolean m_started = false; /*--------------------------------------------------------------- * Runnable Method *-------------------------------------------------------------*/ public void run() { m_started = true; while(true) { System.out.println( Main.getRes().getString( "{0} running", Thread.currentThread().getName() ) ); try { Thread.sleep(500); } catch (InterruptedException e) { } } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Daemon Thread Test Running..." ) ); System.out.println( Main.getRes().getString( "Launching background daemon threads..." ) ); DaemonThreads app = new DaemonThreads(); for (int i = 0; i < 2; i++) { Thread thread = new Thread(app, "App-Thread-" + i); thread.setDaemon(true); thread.start(); } // Wait for at least one of the daemon threads to start to make sure // this main method does not exit prematurely and trigger a JVM // shutdown. while ( !m_started ) { try { Thread.sleep( 10 ); } catch ( InterruptedException e ) { // Ignore. } } System.out.println( Main.getRes().getString( "The JVM should exit momentarily.") ); System.out.println( Main.getRes().getString( "Daemon Thread Test Main Done...") ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/DeadLock.java100644 0 0 11414 12440202301 23671 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2012 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; /** * This is test is designed to simulate a series of deadlock cases which will * can be detected and restarted by the Standard Edition. * * @author Leif Mortenson */ public class DeadLock { private int m_id; private Object m_obj1; private Object m_obj2; private DeadLock( int id, Object obj1, Object obj2 ) { m_id = id; m_obj1 = obj1; m_obj2 = obj2; Thread runner = new Thread( "Locker-" + m_id ) { public void run() { System.out.println( Main.getRes().getString( "Locker-{0}: Started", new Integer( m_id ) ) ); try { lockFirst(); } catch ( Throwable t ) { t.printStackTrace(); } System.out.println( Main.getRes().getString( "Locker-{0}: Complete", new Integer( m_id ) ) ); } }; runner.start(); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ private void lockSecond() { System.out.println( Main.getRes().getString( "Locker-{0}: Try locking {1}...", new Integer( m_id ) , m_obj2.toString() ) ); synchronized( m_obj2 ) { System.out.println( Main.getRes().getString("Locker-{0}: Oops! Locked {1}", new Integer( m_id ), m_obj2.toString() ) ); } } private void lockFirst() { System.out.println( Main.getRes().getString( "Locker-{0}: Locking {1}", new Integer( m_id ) , m_obj1.toString() ) ); synchronized( m_obj1 ) { System.out.println( Main.getRes().getString("Locker-{0}: Locked {1}", new Integer( m_id ), m_obj1.toString() ) ); try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } lockSecond(); } } /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ public static void create2ObjectDeadlock() { Object obj1 = new Object(); Object obj2 = new Object(); new DeadLock( 1, obj1, obj2 ); new DeadLock( 2, obj2, obj1 ); } public static void create3ObjectDeadlock() { Object obj1 = new Object(); Object obj2 = new Object(); Object obj3 = new Object(); new DeadLock( 1, obj1, obj2 ); new DeadLock( 2, obj2, obj3 ); new DeadLock( 3, obj3, obj1 ); } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { System.out.println( Main.getRes().getString("Deadlock Tester Running...")); Object obj1 = new Object(); Object obj2 = new Object(); Object obj3 = new Object(); int exitCode = WrapperManager.getJVMId(); switch ( exitCode ) { case 1: System.out.println( Main.getRes().getString("2-object deadlock.")); create2ObjectDeadlock(); break; case 2: System.out.println( Main.getRes().getString("Wait then 2-object deadlock.")); try { Thread.sleep( 10000 ); } catch ( InterruptedException e ) { } create2ObjectDeadlock(); break; case 3: System.out.println( Main.getRes().getString("3-object deadlock.")); create3ObjectDeadlock(); break; default: System.out.println( Main.getRes().getString("Done.")); } // Always wait a couple seconds to make sure the above threads have time to start. try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString("Main Complete.")); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/DeadLockBase.java100644 0 0 16414 12440202301 24471 0ustar 0 0 package org.tanukisoftware.wrapper.test; import java.lang.reflect.InvocationTargetException; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * This is test is designed to simulate various deadlock cases using either * ReentrantLock instances or synchronized objects. * * @author Leif Mortenson */ public class DeadLockBase { private Integer m_id; private Object m_lock1; private Object m_lock2; private static Class rentrantLockClass; static { try { rentrantLockClass = Class.forName( "java.util.concurrent.locks.ReentrantLock" ); } catch ( ClassNotFoundException e ) { e.printStackTrace(); } } private DeadLockBase( int id, Object lock1, Object lock2 ) { m_id = new Integer( id ); m_lock1 = lock1; m_lock2 = lock2; Thread runner = new Thread( "Locker-" + m_id ) { public void run() { System.out.println( Main.getRes().getString( "Locker-{0}: Started", m_id ) ); try { firstLock(); } catch ( Throwable t ) { t.printStackTrace(); } System.out.println( Main.getRes().getString( "Locker-{0}: Complete", m_id ) ); } }; runner.start(); // Always sleep for a moment to try and keep the test cases running consistently. try { Thread.sleep( 50 ); } catch ( InterruptedException e ) { } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ private void secondLocked() { System.out.println( Main.getRes().getString( "Locker-{0}: Oops! Locked {1}", m_id, m_lock2.toString() ) ); } private void secondLock() { System.out.println( Main.getRes().getString( "Locker-{0}: Try locking {1}...", m_id, m_lock2.toString() ) ); try { if ( rentrantLockClass.isInstance( m_lock2 ) ) { Object lock2 = m_lock2; rentrantLockClass.getMethod( "lock", null ).invoke( lock2, ( Object[] ) null ); try { secondLocked(); } finally { rentrantLockClass.getMethod( "unlock", null ).invoke( lock2, ( Object[] ) null ); } } else { synchronized ( m_lock2 ) { secondLocked(); } } } catch ( NoSuchMethodException nsme ) { nsme.printStackTrace(); } catch ( IllegalArgumentException e ) { e.printStackTrace(); } catch ( SecurityException e ) { e.printStackTrace(); } catch ( IllegalAccessException e ) { e.printStackTrace(); } catch ( InvocationTargetException e ) { e.printStackTrace(); } } private void firstLocked() { System.out.println( Main.getRes().getString( "Locker-{0}: Locked {1}", m_id, m_lock1.toString() ) ); try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } secondLock(); } private void firstLock() { System.out.println( Main.getRes().getString( "Locker-{0}: Locking {1}", m_id, m_lock1.toString() ) ); if ( rentrantLockClass.isInstance( m_lock1 ) ) { try { Object lock1 = m_lock1; rentrantLockClass.getMethod( "lock", null ).invoke( lock1, ( Object[] ) null ); try { firstLocked(); } finally { rentrantLockClass.getMethod( "unlock", null ).invoke( lock1, ( Object[] ) null ); } } catch ( NoSuchMethodException nsme ) { nsme.printStackTrace(); } catch ( IllegalArgumentException e ) { e.printStackTrace(); } catch ( SecurityException e ) { e.printStackTrace(); } catch ( IllegalAccessException e ) { e.printStackTrace(); } catch ( InvocationTargetException e ) { e.printStackTrace(); } } else { synchronized ( m_lock1 ) { firstLocked(); } } } /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ private static Object createLock( boolean reentrant ) { if ( reentrant ) { try { return rentrantLockClass.newInstance(); } catch ( InstantiationException e ) { e.printStackTrace(); } catch ( IllegalAccessException e ) { e.printStackTrace(); } return null; } else { return new Object(); } } public static void create2ObjectDeadlock( boolean reentrant1, boolean reentrant2 ) { Object lock1 = createLock( reentrant1 ); Object lock2 = createLock( reentrant2 ); new DeadLockBase( 1, lock1, lock2 ); new DeadLockBase( 2, lock2, lock1 ); } public static void create3ObjectDeadlock( boolean reentrant1, boolean reentrant2, boolean reentrant3 ) { Object lock1 = createLock( reentrant1 ); Object lock2 = createLock( reentrant2 ); Object lock3 = createLock( reentrant3 ); new DeadLockBase( 1, lock1, lock2 ); new DeadLockBase( 2, lock2, lock3 ); new DeadLockBase( 3, lock3, lock1 ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/DeadLockMixed.java100644 0 0 7121 12440202301 24640 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; /** * This is test is designed to simulate a series of deadlock cases using * ReentrantLocks, which will can be detected and restarted by the Standard * Edition. * * @author Leif Mortenson */ public class DeadLockMixed { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { System.out.println( Main.getRes().getString( "Deadlock Tester Running..." ) ); int exitCode = WrapperManager.getJVMId(); switch ( exitCode ) { case 1: System.out.println( Main.getRes().getString( "2-object deadlock (owned, reentrant)." ) ); DeadLockBase.create2ObjectDeadlock( false, true ); break; case 2: System.out.println( Main.getRes().getString( "2-object deadlock (reentrant, owned)." ) ); DeadLockBase.create2ObjectDeadlock( true, false ); break; case 3: System.out.println( Main.getRes().getString( "3-object deadlock (owned, owned, reentrant)." ) ); DeadLockBase.create3ObjectDeadlock( false, false, true ); break; case 4: System.out.println( Main.getRes().getString( "3-object deadlock (owned, reentrant, owned)." ) ); DeadLockBase.create3ObjectDeadlock( false, true, false ); break; case 5: System.out.println( Main.getRes().getString( "3-object deadlock (reentrant, owned, owned)." ) ); DeadLockBase.create3ObjectDeadlock( true, false, false ); break; case 6: System.out.println( Main.getRes().getString( "3-object deadlock (reentrant, owned, reentrant)." ) ); DeadLockBase.create3ObjectDeadlock( true, false, true ); break; case 7: System.out.println( Main.getRes().getString( "3-object deadlock (reentrant, reentrant, owned)." ) ); DeadLockBase.create3ObjectDeadlock( true, true, false ); break; case 8: System.out.println( Main.getRes().getString( "3-object deadlock (owned, reentrant, reentrant)." ) ); DeadLockBase.create3ObjectDeadlock( false, true, true ); break; default: System.out.println( Main.getRes().getString( "Done." ) ); return; } // Always wait a couple seconds to make sure the above threads have time to start. try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Threads Launched." ) ); // Always wait long enough for the deadlock to be detected. Expecting a 10 second interval. try { Thread.sleep( 10000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Failed to detect a deadlock." ) ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/DeadLockObject.java100644 0 0 5124 12440202301 25001 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; /** * This is test is designed to simulate a series of deadlock cases using standard * Object synchronization, which will can be detected and restarted by the Standard * Edition. * * @author Leif Mortenson */ public class DeadLockObject { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { System.out.println( Main.getRes().getString( "Deadlock Tester Running..." ) ); int exitCode = WrapperManager.getJVMId(); switch ( exitCode ) { case 1: System.out.println( Main.getRes().getString( "2-object deadlock." ) ); DeadLockBase.create2ObjectDeadlock( false, false ); break; case 2: System.out.println( Main.getRes().getString( "Wait then 2-object deadlock." ) ); try { Thread.sleep( 10000 ); } catch ( InterruptedException e ) { } DeadLockBase.create2ObjectDeadlock( false, false ); break; case 3: System.out.println( Main.getRes().getString( "3-object deadlock." ) ); DeadLockBase.create3ObjectDeadlock( false, false, false ); break; default: System.out.println( Main.getRes().getString( "Done." ) ); return; } // Always wait a couple seconds to make sure the above threads have time to start. try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Threads Launched." ) ); // Always wait long enough for the deadlock to be detected. Expecting a 10 second interval. try { Thread.sleep( 10000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Failed to detect a deadlock." ) ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/DeadLockReentrantLock.java100644 0 0 5103 12440202301 26343 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; /** * This is test is designed to simulate a series of deadlock cases using * ReentrantLocks, which will can be detected and restarted by the Standard * Edition. * * @author Leif Mortenson */ public class DeadLockReentrantLock { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { System.out.println( Main.getRes().getString( "Deadlock Tester Running..." ) ); int exitCode = WrapperManager.getJVMId(); switch ( exitCode ) { case 1: System.out.println( Main.getRes().getString( "2-object deadlock." ) ); DeadLockBase.create2ObjectDeadlock( true, true ); break; case 2: System.out.println( Main.getRes().getString( "Wait then 2-object deadlock." ) ); try { Thread.sleep( 10000 ); } catch ( InterruptedException e ) { } DeadLockBase.create2ObjectDeadlock( true, true ); break; case 3: System.out.println( Main.getRes().getString( "3-object deadlock." ) ); DeadLockBase.create3ObjectDeadlock( true, true, true ); break; default: System.out.println( Main.getRes().getString( "Done." ) ); return; } // Always wait a couple seconds to make sure the above threads have time to start. try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Threads Launched." ) ); // Always wait long enough for the deadlock to be detected. Expecting a 10 second interval. try { Thread.sleep( 10000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Failed to detect a deadlock." ) ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/DeadlockPrintStream.java100644 0 0 6677 12440202301 26121 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.IOException; import java.io.PrintStream; /** * A print stream which can be put into a state in which all calls to write * to it will result in the calling threads deadlocking in the call. * Obviously, this class will not be useful to many as it is for tests. * * @author Leif Mortenson */ public class DeadlockPrintStream extends PrintStream { /** The Wrapped PrintStream. */ private PrintStream m_out; /** True if calling threads should be deadlocked. */ private boolean m_deadlock; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ /** * Creates a new DeadlockPrintStream wrapped around another PrintStream. * * @param out The PrintStream which will be wrapped by this new stream. */ public DeadlockPrintStream( PrintStream out ) { super( out ); m_out = out; } /*--------------------------------------------------------------- * PrintStream Methods *-------------------------------------------------------------*/ public void write( int b ) { deadlock(); m_out.write( b ); } public void write( byte[] b ) throws IOException { deadlock(); m_out.write( b ); } public void write( byte[] b, int off, int len ) { deadlock(); m_out.write( b, off, len ); } public void flush() { deadlock(); m_out.flush(); } public void close() { deadlock(); m_out.close(); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * This call will not return as long as the m_deadLock flag is set. * If it is ever cleared with a call to setDeadlock(), stuck threads * will all be released. */ private void deadlock() { if ( m_deadlock ) { synchronized( this ) { while( m_deadlock ) { try { this.wait(); } catch ( InterruptedException e ) { // Ignore } } } } } /** * Sets or clears the deadlock flag. If set, calls to any other method * of this class will result in the calling thread being deadlocked. * They will be released if the flag is cleared with this method. * * @param deadlock True to set the flag, false to clear it. */ public void setDeadlock( boolean deadlock ) { m_deadlock = deadlock; if ( !m_deadlock ) { synchronized( this ) { // Release any threads that are waiting. this.notifyAll(); } } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/DelayedIORestarter.java100644 0 0 5424 12440202301 25702 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.IOException; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperPropertyUtil; /** * This test is designed to make sure the Wrapper handles the case where the * JVM is restarted while the Wrapper is blocking due to a long disk IO queue. * Prior to 3.5.11, the Wrapper would sometimes exit before it noticed that * the JVM had wanted to restart. * * @author Leif Mortenson */ public class DelayedIORestarter { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { // Let everything start up correctly. TestUtils.sleep( 2000 ); int pauseDelay; boolean restart; switch ( WrapperManager.getJVMId() ) { case 1: pauseDelay = 1; restart = true; break; case 2: pauseDelay = 5; restart = true; break; case 3: pauseDelay = 10; restart = true; break; default: pauseDelay = 10; restart = false; break; } System.out.println( Main.getRes().getString( "Asking Wrapper to pause logger for {0} seconds.", new Integer( pauseDelay ) ) ); try { TestUtils.writeWrapperTestCommand( "PAUSE_LOGGER " + pauseDelay ); } catch ( IOException e ) { e.printStackTrace(); } int pollInterval = WrapperPropertyUtil.getIntProperty( "wrapper.commandfile.poll_interval", 5 ) + 1; if ( restart ) { System.out.println( Main.getRes().getString( "Restart JVM after {0} second delay...", new Integer( pollInterval ) ) ); } else { System.out.println( Main.getRes().getString( "Stop JVM after {0} second delay...", new Integer( pollInterval ) ) ); } // Give the Wrapper time to notice the command file. TestUtils.sleep( pollInterval * 1000 ); if ( restart ) { WrapperManager.restart(); } else { WrapperManager.stop( 0 ); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/EnvironmentVariables.java100644 0 0 12063 12440202301 26361 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.util.Properties; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import org.tanukisoftware.wrapper.WrapperManager; /** * * * @author Leif Mortenson */ public class EnvironmentVariables { private static Properties _env = null; /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println("user.language=" + System.getProperty("user.language")); System.out.println("user.region=" + System.getProperty("user.region")); System.out.println(Main.getRes().getString( "Locale=" ) + java.util.Locale.getDefault()); System.out.println(Main.getRes().getString( "Looking for environment variables..." ) ); try { getEnvironmentVariables(); } catch (IOException e) { System.out.println(e.getMessage()); } boolean passed = false; if (_env != null) { System.out.println(); passed = check("ENV_VAR_1", "a"); passed = check("ENV_VAR_2", "b"); passed = check("ENV_VAR_3", "c"); passed = check("ENV_VAR_4", "d"); System.out.println(); } if (passed) { System.out.println( Main.getRes().getString( "Environment variables test passed." ) ); } else { System.out.println( Main.getRes().getString( "Environment variables test FAILED." ) ); } System.out.println( Main.getRes().getString( "Request a JVM restart." ) ); WrapperManager.restart(); } private static boolean check(String variable, String expected) { String actual = _env.getProperty(variable); System.out.print(variable + " = " + actual + ": "); if (expected.equals(actual)) { System.out.println("OK"); return true; } System.out.println(Main.getRes().getString( "FAILED (expected: {0})", expected ) ); return false; } private static void getEnvironmentVariables() throws IOException { String os = System.getProperty("os.name").toLowerCase(); System.out.println(Main.getRes().getString( "Platform is {0}.", os ) ); Process p = null; if (os.indexOf("windows 9") > -1) { p = Runtime.getRuntime().exec("command.com /c set"); } else if (os.indexOf("unix") > -1) { p = Runtime.getRuntime().exec("/bin/env"); } else if ((os.indexOf("nt") > -1) || (os.indexOf("windows 2000") > -1) || (os.indexOf("windows xp") > -1) || (os.indexOf("windows 2003") > -1) ) { p = Runtime.getRuntime().exec("cmd.exe /c set"); } else if (os.indexOf("unix") > -1) { p = Runtime.getRuntime().exec("/bin/env"); } else if ((os.indexOf("linux") > -1) || (os.indexOf("mac os x") > -1) || (os.indexOf("freebsd") > -1)) { p = Runtime.getRuntime().exec("/usr/bin/env"); } if (p == null) { System.out.println(Main.getRes().getString( "Don't know how to read environment variables on this platform: {0}", os ) ); return; } _env = new Properties(); BufferedReader br=new BufferedReader(new InputStreamReader(p.getInputStream())); String line = null; while ((line = br.readLine()) != null) { int idx = line.indexOf('='); if (idx > -1) { String key = line.substring(0, idx); String value = line.substring(idx + 1); _env.setProperty(key, value); } } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/ExecThrasher.java100644 0 0 17631 12440202301 24617 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperJNIError; import org.tanukisoftware.wrapper.WrapperLicenseError; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperProcess; import org.tanukisoftware.wrapper.WrapperProcessConfig; import org.tanukisoftware.wrapper.WrapperSystemPropertyUtil; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.util.Random; /** * * * @author Leif Mortenson */ public class ExecThrasher { private static String c_simplewaiter; private static String c_encoding; private static String c_startTypeS; private static int c_startType; private static int c_threadCount; /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ static { if ( WrapperManager.isWindows() ) { c_simplewaiter = "../test/simplewaiter.exe"; } else { c_simplewaiter = "../test/simplewaiter"; } // In order to read the output from some processes correctly we need to get the correct encoding. // On some systems, the underlying system encoding is different than the file encoding. c_encoding = System.getProperty( "sun.jnu.encoding" ); if ( c_encoding == null ) { c_encoding = System.getProperty( "file.encoding" ); if ( c_encoding == null ) { // Default to Latin1 c_encoding = "Cp1252"; } } // Resolve the start type. c_startTypeS = WrapperSystemPropertyUtil.getStringProperty( ExecThrasher.class.getName() + ".startType", "" ); if ( c_startTypeS.equals( "POSIX_SPAWN" ) ) { c_startType = WrapperProcessConfig.POSIX_SPAWN; } else if ( c_startTypeS.equals( "FORK_EXEC" ) ) { c_startType = WrapperProcessConfig.FORK_EXEC; } else if ( c_startTypeS.equals( "VFORK_EXEC" ) ) { c_startType = WrapperProcessConfig.VFORK_EXEC; } else { c_startType = WrapperProcessConfig.DYNAMIC; c_startTypeS = "DYNAMIC"; } // Resolve the thread count. c_threadCount = WrapperSystemPropertyUtil.getIntProperty( ExecThrasher.class.getName() + ".threadCount", 100 ); } private static void handleInputStream( final InputStream is, final String encoding, final String label ) { Thread runner = new Thread() { public void run() { BufferedReader br; String line; try { br = new BufferedReader( new InputStreamReader( is, encoding ) ); try { while ( ( line = br.readLine() ) != null ) { System.out.println( label + ": " + line ); } } finally { br.close(); } } catch ( IOException e ) { e.printStackTrace(); } System.out.println( label + " EOF" ); } }; runner.start(); } private static void handleWrapperProcessInner( WrapperProcess process, long timeoutMS, int threadId, int processId ) throws IOException { try { handleInputStream( process.getInputStream(), c_encoding, "Thrasher Thread #" + threadId + " Process #" + processId + " stdout" ); handleInputStream( process.getErrorStream(), c_encoding, "Thrasher Thread #" + threadId + " Process #" + processId + " stderr" ); if ( timeoutMS > 0 ) { long start = System.currentTimeMillis(); while ( process.isAlive() && ( System.currentTimeMillis() - start < timeoutMS ) ) { try { Thread.sleep( 100 ); } catch ( InterruptedException e ) { } } if ( process.isAlive() ) { System.out.println( "Thrasher Thread #" + threadId + " Process #" + processId + " Timed out waiting for child. Destroying." ); process.destroy(); } } } finally { try { int exitCode = process.waitFor(); System.out.println( "Thrasher Thread #" + threadId + " Process #" + processId + " exitCode: " + exitCode ); } catch ( InterruptedException e ) { System.out.println( "Thrasher Thread #" + threadId + " Process #" + processId + " Timed out waiting for process to complete." ); } } } private static void handleWrapperProcess( String command, long timeoutMS, int threadId, int processId ) throws IOException { WrapperProcessConfig processConfig = new WrapperProcessConfig(); processConfig.setStartType( c_startType ); WrapperProcess process = WrapperManager.exec( command, processConfig ); handleWrapperProcessInner( process, timeoutMS, threadId, processId ); } private static void thrasher( int threadId ) { // We want to work in a repeatable way. Random rand = new Random( threadId ); System.out.println( "Thrasher Thread #" + threadId + " Begin" ); try { for ( int processId = 0; processId < 1000; processId++ ) { int seconds = rand.nextInt( 10 ); String command = c_simplewaiter + " 0 " + seconds; System.out.println( "Thrasher Thread #" + threadId + " Process #" + processId + " Launch (" + seconds + " seconds)" ); try { handleWrapperProcess( command, ( seconds + 5 ) * 1000, threadId, processId ); } catch ( IOException e ) { System.out.println( "Thrasher Thread #" + threadId + " Process #" + processId + " Launch Failed." ); e.printStackTrace(); } } } finally { System.out.println( "Thrasher Thread #" + threadId + " End" ); } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { System.out.println( "Communicate with child processes using encoding: " + c_encoding ); System.out.println( "Using start type '" + c_startTypeS + "'." ); System.out.println( "Launching " + c_threadCount + " threads..." ); for ( int i = 0; i < c_threadCount; i++ ) { final int threadId = i; Thread thread = new Thread( "ExecThrasher-" + i ) { public void run() { thrasher( threadId ); } }; thread.start(); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/Filter.java100644 0 0 7512 12440202301 23434 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; /** * * * @author Leif Mortenson */ public class Filter { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Test the handling of filters." ) ); System.out.println( Main.getRes().getString( "The Wrapper should restart the JVM when it detects either the string:" ) ); System.out.println( Main.getRes().getString( " \"ERR OR\" or \"N ice long restart message.\", both without the" ) ); System.out.println( Main.getRes().getString( " extra space. It should ignore the string: \"NONERROR\". Then" ) ); System.out.println( Main.getRes().getString( " it should exit when it detects the string: \"ALL DONE\", once again" ) ); System.out.println( Main.getRes().getString( " without the space." ) ); System.out.println(); System.out.println( Main.getRes().getString( "The next line should be ignored:" ) ); System.out.println( " NONERROR"); System.out.println(); if (WrapperManager.getJVMId() >= 6) { // Time to shutdown System.out.println( Main.getRes().getString( "The next line should cause the Wrapper to exit:" ) ); System.out.println(" ALLDONE"); } else if (WrapperManager.getJVMId() == 5) { // Perform a restart. System.out.println( Main.getRes().getString( "The next line should cause the Wrapper to restart the JVM:" ) ); System.out.println( " HEAD and a bunch of stuff before the TAIL" ); } else if (WrapperManager.getJVMId() == 4) { // Perform a thread dump and restart. System.out.println( Main.getRes().getString( "The next line should cause the Wrapper to invoke a thread dump and then restart the JVM:" ) ); System.out.println( " DUMP -n- RESTART" ); } else if (WrapperManager.getJVMId() == 3) { // Try a restart with spaces. System.out.println( Main.getRes().getString( "The next line should cause the Wrapper to restart the JVM:" ) ); System.out.println( " Nice long restart message." ); } else { System.out.println( Main.getRes().getString( "The next line should cause the Wrapper to restart the JVM:" ) ); System.out.println(" ERROR"); } System.out.println(); System.out.println( Main.getRes().getString( "The above message should be caught before this line, but this line" ) ); System.out.println( Main.getRes().getString( " will still be visible. Wait for 5 seconds before this thread is" ) ); System.out.println( Main.getRes().getString( " allowed to complete. This prevents the Wrapper from detecting" ) ); System.out.println( Main.getRes().getString( " that the application has completed and exiting normally. The" ) ); System.out.println( Main.getRes().getString( " Wrapper will try to shutdown the JVM cleanly, so it will not exit" ) ); System.out.println( Main.getRes().getString( " until this thread has completed." ) ); try { Thread.sleep(5000); } catch (InterruptedException e) { } System.out.println( Main.getRes().getString( "Main complete." ) ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/GrowingLogOutput.java100644 0 0 5256 12440202301 25511 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.util.Date; import java.text.SimpleDateFormat; /** * * * @author Leif Mortenson */ public class GrowingLogOutput { /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ private static String lPad( int n, int len, String padding ) { String s = Integer.toString( n ); int len2 = s.length(); if ( len2 < len ) { return padding.substring( 0, len - len2 ) + s; } else { return s; } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { // This class is not localized so we can run it without the Wrapper code. System.out.println( "Log several lines of output of growing length. This is to massage the internal logging buffers." ); SimpleDateFormat df = new SimpleDateFormat( "HH:mm:ss.SSS" ); // Build up a long base string. We will be sending varying substring instances of this to the output. StringBuffer messageSB = new StringBuffer(); for ( int i = 0; i < 1000; i++ ) { messageSB.append( "ThisIsAVeryLongStringWithoutSpaces." ); // 35 chars } String message = messageSB.toString(); // 35000 chars. int messageLen = message.length(); long allStart = System.currentTimeMillis(); System.out.println( df.format( new Date() ) + " Starting..." ); for ( int subMessageLen = 0; subMessageLen < messageLen; subMessageLen++ ) { String subMessage = message.substring( 0, subMessageLen ); System.out.println( df.format( new Date() ) + " " + lPad( subMessageLen + 20, 6, " " ) + ":" + subMessage ); } long allTime = System.currentTimeMillis() - allStart; System.out.println( df.format( new Date() ) + " Max length should be: " + ( messageLen - 1 + 20 ) ); System.out.println( df.format( new Date() ) + " Total time: " + allTime ); System.out.println( df.format( new Date() ) + " All done." ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/HugeLogOutput.java100644 0 0 5055 12440202301 24762 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.text.SimpleDateFormat; import java.util.Date; import org.tanukisoftware.wrapper.WrapperManager; /** * * * @author Leif Mortenson */ public class HugeLogOutput { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { // 62 chars long String subStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; // This first test is to check for buffer problems increasing the size of the Wrapper's log buffer. System.out.println( "Print out 10 long lines of increasing length." ); // Now loop and print this to the console 10 times. Log the time before each line. StringBuffer sb = new StringBuffer(); SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS" ); for ( int i = 0; i < 10; i++ ) { for ( int j = 0; j < 10; j++ ) { sb.append( subStr ); } String longStr = sb.toString(); System.out.println( df.format( new Date() ) ); System.out.println( longStr ); } // This next test is to check for a speed problem which used to exist with VERY large log lines. // Loop printing out 10 lines of increasing length. System.out.println( "Print out 10 very long lines of output." ); sb = new StringBuffer(); for ( int j = 0; j < 10; j++ ) { // Increase the size of the buffer by 100,006 chars each cyle (62*1613 copies) // After the 10th loop, it will be 1,000,060 chars long. for ( int i = 0; i < 1613; i++ ) { sb.append( subStr ); } String hugeStr = sb.toString(); System.out.println(); System.out.println( "Loop #" + j + " Size: " + hugeStr.length() ); System.out.println( df.format( new Date() ) ); System.out.println( hugeStr ); } System.out.println( "All done." ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/JarMain.java100644 0 0 3457 12440202301 23534 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * * * @author Leif Mortenson */ public class JarMain { static { if ( System.getProperty( "JarMain.init.fail" ) != null ) { System.out.println( Main.getRes().getString( "About to throw exception in initializer..." ) ); throw new IllegalStateException( Main.getRes().getString( "This is an intentional error in the initializer." ) ); } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { if ( args.length > 0 ) { System.out.println( Main.getRes().getString( "Arguments:" ) ); for ( int i = 0; i < args.length; i++ ) { System.out.println( " args[" + i + "]=" + args[i] ); } } System.out.println( Main.getRes().getString( "Loop for 10 seconds." ) ); for ( int i = 0; i < 10; i++ ) { try { Thread.sleep(1000); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Counting...{0}", new Integer( i ) ) ); } System.out.println( Main.getRes().getString( "Loop complete." ) ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/LoadedGCOutput.java100644 0 0 3376 12440202301 25036 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * * * @author Leif Mortenson */ public class LoadedGCOutput { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "This test is to make sure that large amounts of GCs with -verbose:gc\nenabled do not cause extra line feeds in output." ) ); System.out.println(); System.out.println( Main.getRes().getString( "This test will run indefinitely." ) ); try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } for ( int i = 0; i < 10; i++ ) { // Start another thread to keep things busy creating lots of objects. Thread runner = new Thread( "LoadedGCOutput-busy-bee-" + i ) { public void run() { while ( true ) { Object test = new Object(); } } }; runner.setDaemon( true ); runner.start(); } while ( true ) { System.gc(); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/LoadedLogOutput.java100644 0 0 3200 12440202301 25250 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; /** * * * @author Leif Mortenson */ public class LoadedLogOutput { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { DateFormat df = new SimpleDateFormat( "yyyyMMdd'T'HHmmssSSS" ); /* // Let the JVM inform the Wrapper that it is started. try { Thread.sleep( 1500 ); } catch ( InterruptedException e ) { } */ long start = System.currentTimeMillis(); long now = start; System.out.println( Main.getRes().getString( "Log as much as possible for 60 seconds..." ) ); int line = 1; while ( now - start < 60000 ) { System.out.println( ( line++ ) + " : " + ( now - start ) + " : " + df.format( new Date( now ) ) + " : ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890" ); now = System.currentTimeMillis(); } System.out.println( Main.getRes().getString( "All done.") ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/LoadedSplitOutput.java100644 0 0 5013 12440202301 25626 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * * * @author Leif Mortenson */ public class LoadedSplitOutput { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { int maxDelay = 16384; System.out.println( Main.getRes().getString( "This test is to make sure that the Wrapper handles lines of split output correctly, only adding line feeds when the split delay is longer than the configured wrapper.log.lf_delay.threshold." ) ); System.out.println(); System.out.println( Main.getRes().getString( "This test will loop with delays between 1ms and {0}ms at increasing increments.", new Integer( maxDelay ) ) ); System.out.println(); try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { } int delay = 1; while ( delay <= maxDelay ) { System.out.print( "Head then delay for " + delay + "ms ..." ); try { Thread.sleep( delay ); } catch ( InterruptedException e ) { } System.out.println( "... Complete the line." ); delay += delay; } System.out.println(); System.out.println( Main.getRes().getString( "Print a progress bar with delays between 1ms and {0}ms at increasing increments.", new Integer( maxDelay ) ) ); System.out.println(); delay = 1; while ( delay <= maxDelay ) { System.out.print( "Start with " + delay + "ms delay." ); for ( int i = 0; i < 10; i++ ) { try { Thread.sleep( delay ); } catch ( InterruptedException e ) { } System.out.print( "." ); } System.out.println( " Done." ); delay += delay; } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/LoadedWrapperListener.java100644 0 0 27270 12440202301 26471 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import org.tanukisoftware.wrapper.WrapperListener; import org.tanukisoftware.wrapper.WrapperManager; /** * This test was created to test timeout problems under heavily loaded * conditions. * * @author Leif Mortenson */ public class LoadedWrapperListener implements WrapperListener, Runnable { private String[] m_startMainArgs; private boolean m_mainComplete; private Integer m_mainExitCode; private boolean m_waitTimedOut; /*--------------------------------------------------------------- * Constructor *-------------------------------------------------------------*/ private LoadedWrapperListener() { } /*--------------------------------------------------------------- * WrapperListener Methods *-------------------------------------------------------------*/ /** * The start method is called when the WrapperManager is signaled by the * native wrapper code that it can start its application. This * method call is expected to return, so a new thread should be launched * if necessary. * * @param args List of arguments used to initialize the application. * * @return Any error code if the application should exit on completion * of the start method. If there were no problems then this * method should return null. */ public Integer start( String[] args ) { if ( WrapperManager.isDebugEnabled() ) { System.out.println( Main.getRes().getString( "LoadedWrapperListener: start(args)" ) ); } Thread mainThread = new Thread( this, "LoadedWrapperListenerMain" ); synchronized ( this ) { m_startMainArgs = args; mainThread.start(); // Wait for five seconds to give the application a chance to have failed. try { this.wait( 5000 ); } catch ( InterruptedException e ) { } m_waitTimedOut = true; if ( WrapperManager.isDebugEnabled() ) { System.out.println( Main.getRes().getString( "LoadedWrapperListener: start(args) end. Main Completed={0}, exitCode={1}", new Object[]{ new Boolean( m_mainComplete ), m_mainExitCode } ) ); } return m_mainExitCode; } } /** * Called when the application is shutting down. The Wrapper assumes that * this method will return fairly quickly. If the shutdown code code * could potentially take a long time, then WrapperManager.signalStopping() * should be called to extend the timeout period. If for some reason, * the stop method can not return, then it must call * WrapperManager.stopped() to avoid warning messages from the Wrapper. * * @param exitCode The suggested exit code that will be returned to the OS * when the JVM exits. * * @return The exit code to actually return to the OS. In most cases, this * should just be the value of exitCode, however the user code has * the option of changing the exit code if there are any problems * during shutdown. */ public int stop( int exitCode ) { if ( WrapperManager.isDebugEnabled() ) { System.out.println( Main.getRes().getString( "LoadedWrapperListener: stop({0})", new Integer( exitCode ) ) ); } return exitCode; } /** * Called whenever the native wrapper code traps a system control signal * against the Java process. It is up to the callback to take any actions * necessary. Possible values are: WrapperManager.WRAPPER_CTRL_C_EVENT, * WRAPPER_CTRL_CLOSE_EVENT, WRAPPER_CTRL_LOGOFF_EVENT, or * WRAPPER_CTRL_SHUTDOWN_EVENT * * @param event The system control signal. */ public void controlEvent( int event ) { if ( WrapperManager.isControlledByNativeWrapper() ) { if ( WrapperManager.isDebugEnabled() ) { System.out.println( Main.getRes().getString( "LoadedWrapperListener: controlEvent({0}) Ignored", new Integer( event ) ) ); } // Ignore the event as the native wrapper will handle it. } else { if ( WrapperManager.isDebugEnabled() ) { System.out.println( Main.getRes().getString( "LoadedWrapperListener: controlEvent({0}) Stopping", new Integer(event) ) ); } // Not being run under a wrapper, so this isn't an NT service and should always exit. // Handle the event here. WrapperManager.stop( 0 ); // Will not get here. } } /*--------------------------------------------------------------- * Runnable Methods *-------------------------------------------------------------*/ /** * Runner thread which actually launches the application. */ public void run() { Throwable t = null; try { if ( WrapperManager.isDebugEnabled() ) { System.out.println( Main.getRes().getString( "LoadedWrapperListener: invoking start main method" ) ); } appMain( m_startMainArgs ); if ( WrapperManager.isDebugEnabled() ) { System.out.println( Main.getRes().getString( "LoadedWrapperListener: start main method completed" ) ); } synchronized ( this ) { // Let the start() method know that the main method returned, in case it is // still waiting. m_mainComplete = true; this.notifyAll(); } return; } catch (Throwable e) { t = e; } // If we get here, then an error was thrown. If this happened quickly // enough, the start method should be allowed to shut things down. System.out.println( Main.getRes().getString( "Encountered an error running start main: {0}", t ) ); t.printStackTrace(); synchronized( this ) { if ( m_waitTimedOut ) { // Shut down here. WrapperManager.stop( 1 ); return; // Will not get here. } else { // Let start method handle shutdown. m_mainComplete = true; m_mainExitCode = new Integer( 1 ); this.notifyAll(); return; } } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ /** * Main method of the actual application. */ private void appMain( String[] args ) { System.out.println( Main.getRes().getString( "App Main Starting." ) ); System.out.println(); // Loop and display 500 long lines of text to place to dump a lot of // output before the CPU starts being loaded down. This will strain // the Wrapper just as the CPU suddenly hpegs at 100%. for ( int i = 0; i < 500; i++ ) { System.out.println( new Date() + Main.getRes().getString( " Pre {0} of output. " , new Integer( i ) ) + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ); } // Start up a thread to thrash the hard disk. Thread diskThrasher = new Thread( "LoadedWrapperListener_DiskThrasher" ) { public void run() { performDiskThrashing(); } }; diskThrasher.start(); // Start up a thread to thrash memory. Thread memoryThrasher = new Thread( "LoadedWrapperListener_MemoryThrasher" ) { public void run() { performMemoryThrashing(); } }; memoryThrasher.start(); // Start up some threads to eat all available CPU for ( int i = 0; i < 4; i++ ) { Thread cpuThrasher = new Thread( "LoadedWrapperListener_CPUThrasher_" + i ) { public void run() { performCPUThrashing(); } }; cpuThrasher.start(); } // Loop and display 5000 long lines of text to place a heavy load on the // JVM output processing code of the Wrapper while the above threads are // eating all available CPU. for ( int i = 0; i < 5000; i++ ) { System.out.println( new Date() + " Row " + i + " of output. " + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ); } System.out.println(); System.out.println( Main.getRes().getString( "App Main Complete." ) ); } private void performDiskThrashing() { while( !m_mainComplete ) { File file = new File( "loadedwrapperlistener.dat" ); try { PrintWriter w = new PrintWriter( new FileWriter( file ) ); try { for ( int i = 0; i < 100; i++ ) { w.println( new Date() + Main.getRes().getString( " Row {0} of output. ", new Integer( i ) ) + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ); } } finally { w.close(); } } catch ( IOException e ) { e.printStackTrace(); } file.delete(); } } private void performMemoryThrashing() { while( !m_mainComplete ) { // 200MB block of memory byte[][] garbage = new byte[200][]; for ( int i = 0; i < garbage.length; i++ ) { garbage[i] = new byte[1024 * 1024]; } garbage = null; Runtime runtime = Runtime.getRuntime(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); System.out.println( Main.getRes().getString( "Total Memory=" ) + totalMemory + ", " + Main.getRes().getString( "Used Memory=" ) + ( totalMemory - freeMemory ) ); } } private void performCPUThrashing() { while( !m_mainComplete ) { // Do nothing, we just want a tight loop. } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { // Test an initial line feed as a regression test. Must be // the first output from the JVM System.out.println(); System.out.println( "LoadedWrapperListener.main" ); WrapperManager.start( new LoadedWrapperListener(), args ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/LogOutput.java100644 0 0 11005 12440202301 24161 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import org.tanukisoftware.wrapper.WrapperManager; /** * * * @author Leif Mortenson */ public class LogOutput { private static void sleep() { try { Thread.sleep(2000); } catch (InterruptedException e) {} } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Test the various log levels...") ); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_DEBUG, Main.getRes().getString( "Debug output" ) ); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, Main.getRes().getString( "Info output" ) ); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_STATUS, Main.getRes().getString( "Status output" ) ); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_WARN, Main.getRes().getString( "Warn output" ) ); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_ERROR, Main.getRes().getString( "Error output" ) ); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_FATAL, Main.getRes().getString( "Fatal output" ) ); // Let things catch up as the timing of WrapperManager.log output and System.out // output can not be guaranteed. sleep(); System.out.println(Main.getRes().getString( "Put the logger through its paces..." ) ); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, Main.getRes().getString( "Special C characters in %s %d % %%" ) ); sleep(); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, ""); sleep(); String sa = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, Main.getRes().getString("Long log messages will be clipped at 4096 bytes when the Wrapper reads them.") ); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, ""); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, Main.getRes().getString("Output a 62 * 100 + 2 length string.")); StringBuffer sb = new StringBuffer(); for (int i = 0; i < 100; i++) { sb.append(sa); } WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, "[" + sb + "]" ); sleep(); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, Main.getRes().getString("Output 100 62 character strings with line feeds between each one as a single log message.") ); sb = new StringBuffer(); for (int i = 0; i < 100; i++) { sb.append(sa); sb.append("\n"); } WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, "[" + sb + "]"); sleep(); WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, Main.getRes().getString("Output 100 62 character strings as individual log message.")); for (int i = 0; i < 100; i++) { WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, sa); } WrapperManager.log(WrapperManager.WRAPPER_LOG_LEVEL_INFO, Main.getRes().getString( "Japanese \u300c\u65e5\u672c\u8a9e\u306e\u8a66\u9a13 \u30a2\u30a4\u30a6\u30a8\u30aa\u30ab\u30ad\u30af\u30b1\u30b3\u300d Test" ) ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/LogStdoutStderr.java100644 0 0 4220 12440202301 25310 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * * * @author Leif Mortenson */ public class LogStdoutStderr { private static int m_lineNum = 1; private static int m_outLineNum = 1; private static int m_errLineNum = 1; /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ private static void logOut( String message ) { System.out.println( "All:" + (m_lineNum++) + " Out:" + (m_outLineNum++) + " " + message ); } private static void logErr( String message ) { System.err.println( "All:" + (m_lineNum++) + " Err:" + (m_errLineNum++) + " " + message ); } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Logs several lines of output to stdout and stderr." ) ); System.out.println( Main.getRes().getString( "Make sure that all of the line numbers are in order and that they show up in the right places." ) ); logOut( "Test Output" ); logErr( "Test Error" ); for ( int i = 0; i < 100; i++ ) { logOut( "Loop #" + i ); logErr( "Loop #" + i ); } StringBuffer sb = new StringBuffer(); for ( int i = 0; i < 100; i++ ) { sb.append( "abcdefghijklmnopqrstuvwxyz" ); logOut( "Loop #" + i + " " + sb.toString() ); logErr( "Loop #" + i + " " + sb.toString() ); } logOut( "All done." ); logErr( "All done." ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/LongRunningBackgroundThreads.java100644 0 0 6522 12440202301 27762 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import org.tanukisoftware.wrapper.WrapperManager; /** * Test case which launched several threads and lets them run for 30 seconds. * * @author Leif Mortenson */ public class LongRunningBackgroundThreads implements Runnable { private volatile int m_threadCount; /*--------------------------------------------------------------- * Runnable Method *-------------------------------------------------------------*/ public void run() { m_threadCount++; int loops = 0; while ( loops < 60 ) { loops++; System.out.println( Main.getRes().getString( "{0} loop #{1}", new Object[]{ Thread.currentThread().getName(), new Integer( loops ) } ) ); try { Thread.sleep(500); } catch ( InterruptedException e ) { } } System.out.println(Main.getRes().getString( "{0} stopping", Thread.currentThread().getName() ) ); m_threadCount--; if ( m_threadCount <= 0 ) { System.out.println( Main.getRes().getString( "The JVM and then the wrapper should exit now.") ); } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { System.out.println( Main.getRes().getString( "Long-running Background Threads Running..." ) ); LongRunningBackgroundThreads app = new LongRunningBackgroundThreads(); for ( int i = 0; i < 2; i++ ) { Thread thread = new Thread( app, "App-Thread-" + i ); thread.start(); } System.out.println( Main.getRes().getString( "Running as a service: {0}", new Boolean( WrapperManager.isLaunchedAsService() ) ) ); System.out.println( Main.getRes().getString( "Controlled by wrapper: {0}", new Boolean( WrapperManager.isControlledByNativeWrapper() ) ) ); System.out.println( Main.getRes().getString( "Long-running Background Threads Main Done...") ) ; } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/Main.java100644 0 0 73767 12440202301 23132 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.awt.BorderLayout; import java.awt.Button; import java.awt.Checkbox; import java.awt.Component; import java.awt.Container; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Label; import java.awt.List; import java.awt.Panel; import java.awt.ScrollPane; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import org.tanukisoftware.wrapper.WrapperActionServer; import org.tanukisoftware.wrapper.WrapperListener; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperResources; import org.tanukisoftware.wrapper.WrapperSystemPropertyUtil; import org.tanukisoftware.wrapper.event.WrapperEventListener; /** * This is a Test / Example program which can be used to test the * main features of the Wrapper. *

* It is also an example of Integration Method #3, where you implement * the WrapperListener interface manually. *

* NOTE that in most cases you will want to use Method #1, using the * WrapperSimpleApp helper class to integrate your application. Please * see the integration * section of the documentation for more details. * * @author Leif Mortenson */ public class Main extends AbstractActionApp implements WrapperListener { private WrapperActionServer m_actionServer; private MainFrame m_frame; private ActionRunner m_actionRunner; private static WrapperResources m_res; private List m_listenerFlags; private TextField m_slowSeconds; private TextField m_serviceName; private TextField m_consoleTitle; private TextField m_childCommand; private Checkbox m_childDetached; /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ private Main() { } /*--------------------------------------------------------------- * Inner Classes *-------------------------------------------------------------*/ private class MainFrame extends Frame implements ActionListener, WindowListener { /** * Serial Version UID. */ private static final long serialVersionUID = -3847376282833547574L; MainFrame() { super( getRes().getString( "TestWrapper Example Application" ) ); init(); setLocation( 10, 10 ); setSize( 750, 480 ); setResizable( true ); } private void init() { GridBagLayout gridBag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); Panel panel = new Panel(); panel.setLayout( gridBag ); ScrollPane scrollPane = new ScrollPane(); scrollPane.add( panel ); scrollPane.getHAdjustable().setUnitIncrement( 20 ); scrollPane.getVAdjustable().setUnitIncrement( 20 ); setLayout( new BorderLayout() ); add( scrollPane, BorderLayout.CENTER ); buildCommand( panel, gridBag, c, "Stop(0)", "stop0", getRes().getString( "Calls WrapperManager.stop( 0 ) to shutdown the JVM and Wrapper with a success exit code." ) ); buildCommand( panel, gridBag, c, "Stop(1)", "stop1", getRes().getString( "Calls WrapperManager.stop( 1 ) to shutdown the JVM and Wrapper with a failure exit code." ) ); buildCommand( panel, gridBag, c, "Exit(0)", "exit0", getRes().getString( "Calls System.exit( 0 ) to shutdown the JVM and Wrapper with a success exit code." ) ); buildCommand( panel, gridBag, c, "Exit(1)", "exit1", getRes().getString( "Calls System.exit( 1 ) to shutdown the JVM and Wrapper with a failure exit code." ) ); buildCommand( panel, gridBag, c, "StopImmediate(0)", "stopimmediate0", getRes().getString( "Calls WrapperManager.stopImmediate( 0 ) to immediately shutdown the JVM and Wrapper with a success exit code." ) ); buildCommand( panel, gridBag, c, "StopImmediate(1)", "stopimmediate1", getRes().getString(" Calls WrapperManager.stopImmediate( 1 ) to immediately shutdown the JVM and Wrapper with a failure exit code." ) ); buildCommand( panel, gridBag, c, "StopAndReturn(0)", "stopandreturn0", getRes().getString( "Calls WrapperManager.stopAndReturn( 0 ) to shutdown the JVM and Wrapper with a success exit code." ) ); buildCommand( panel, gridBag, c, "Nested Exit(1)", "nestedexit1", getRes().getString( "Calls System.exit(1) within WrapperListener.stop(1) callback." ) ); buildCommand( panel, gridBag, c, "Halt(0)", "halt0", getRes().getString( "Calls Runtime.getRuntime().halt(0) to kill the JVM, the Wrapper will restart it." ) ); buildCommand( panel, gridBag, c, "Halt(1)", "halt1", getRes().getString( "Calls Runtime.getRuntime().halt(1) to kill the JVM, the Wrapper will restart it." ) ); buildCommand( panel, gridBag, c, "Restart()", "restart", getRes().getString( "Calls WrapperManager.restart() to shutdown the current JVM and start a new one." ) ); buildCommand( panel, gridBag, c, "RestartAndReturn()", "restartandreturn", getRes().getString( "Calls WrapperManager.restartAndReturn() to shutdown the current JVM and start a new one." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Native Access Violation" ), "access_violation_native", getRes().getString( "Causes an access violation using native code, the JVM will crash and be restarted." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Simulate JVM Hang" ), "appear_hung", getRes().getString( "Makes the JVM appear to be hung as viewed from the Wrapper, it will be killed and restarted." ) ); m_slowSeconds = new TextField( "0" ); Panel slowPanel = new Panel(); slowPanel.setLayout( new BorderLayout() ); slowPanel.add( new Label( getRes().getString( "Delay Seconds: " ) ), BorderLayout.WEST ); slowPanel.add( m_slowSeconds, BorderLayout.CENTER ); Panel slowPanel2 = new Panel(); slowPanel2.setLayout( new BorderLayout() ); slowPanel2.add( slowPanel, BorderLayout.WEST ); slowPanel2.add( new Label( getRes().getString( "Makes the JVM appear sluggish by being slow to respond to all packet requests from the Wrapper." ) ), BorderLayout.CENTER ); buildCommand( panel, gridBag, c, getRes().getString( "Simulate Slow JVM" ), "appear_slow", slowPanel2 ); buildCommand( panel, gridBag, c, getRes().getString( "Create Deadlock" ), "deadlock", getRes().getString( "Creates two new threads which intentionally go into a DeadLock situation. (Standard, Professional)" ) ); buildCommand( panel, gridBag, c, getRes().getString("Simulate Out Of Memory" ), "outofmemory", getRes().getString( "Throws an OutOfMemoryError to demonstrate the Trigger feature." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Ignore Control Events" ), "ignore_events", getRes().getString( "Makes this application ignore control events. It will not shutdown in response to CTRL-C. The Wrapper will still respond." ) ); buildCommand( panel, gridBag, c,getRes().getString( "Request Thread Dump" ), "dump", getRes().getString( "Calls WrapperManager.requestThreadDump() to cause the JVM to dump its current thread state." ) ); buildCommand( panel, gridBag, c, getRes().getString( "System.out Deadlock" ), "deadlock_out", getRes().getString( "Simulates a failure mode where the System.out object has become deadlocked." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Poll Users" ), "users", getRes().getString( "Begins calling WrapperManager.getUser() and getInteractiveUser() to monitor the current and interactive users." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Poll Users with Groups" ), "groups", getRes().getString( "Same as above, but includes information about the user's groups." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Console" ), "console", getRes().getString( "Prompt for Actions in the console." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Idle" ), "idle", getRes().getString( "Run idly." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Dump Properties" ), "properties", getRes().getString( "Dumps all System Properties to the console." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Dump Configuration" ), "configuration", getRes().getString( "Dumps all Wrapper Configuration Properties to the console." ) ); m_listenerFlags = new List( 2, true ); m_listenerFlags.add( "Service" ); m_listenerFlags.add( "Control" ); m_listenerFlags.add( "Logging" ); m_listenerFlags.add( "Core" ); Panel flagPanel = new Panel(); flagPanel.setLayout( new BorderLayout() ); flagPanel.add( new Label( "Event Flags: " ), BorderLayout.WEST ); flagPanel.add( m_listenerFlags, BorderLayout.CENTER ); flagPanel.setSize( 100, 10 ); Panel flagPanel2 = new Panel(); flagPanel2.setLayout( new BorderLayout() ); flagPanel2.add( flagPanel, BorderLayout.WEST ); buildCommand( panel, gridBag, c, getRes().getString( "Update Event Listener" ), "listener", flagPanel2 ); buildCommand( panel, gridBag, c, getRes().getString( "Service List" ), "service_list", getRes().getString( "Displays a list of registered services on Windows." ) ); m_serviceName = new TextField( "testwrapper" ); Panel servicePanel = new Panel(); servicePanel.setLayout( new BorderLayout() ); servicePanel.add( new Label( getRes().getString( "Interrogate Service. Service name: " ) ), BorderLayout.WEST ); servicePanel.add( m_serviceName, BorderLayout.CENTER ); Panel servicePanel2 = new Panel(); servicePanel2.setLayout( new BorderLayout() ); servicePanel2.add( servicePanel, BorderLayout.WEST ); buildCommand( panel, gridBag, c, getRes().getString( "Service Interrogate" ), "service_interrogate", servicePanel2 ); buildCommand( panel, gridBag, c, getRes().getString( "Service Start" ), "service_start", getRes().getString( "Starts the above service." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Service Stop" ), "service_stop", getRes().getString( "Stops the above service." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Service User Code" ), "service_user", getRes().getString( "Sends a series of user codes to the above service." ) ); m_consoleTitle = new TextField( getRes().getString( "Java Service Wrapper" ) ); Panel titlePanel = new Panel(); titlePanel.setLayout( new BorderLayout() ); titlePanel.add( new Label( getRes().getString( "Console Title: " ) ), BorderLayout.WEST ); titlePanel.add( m_consoleTitle, BorderLayout.CENTER ); Panel titlePanel2 = new Panel(); titlePanel2.setLayout( new BorderLayout() ); titlePanel2.add( titlePanel, BorderLayout.WEST ); buildCommand( panel, gridBag, c, getRes().getString( "Set Console Title" ), "console_title", titlePanel2 ); m_childCommand = new TextField( getRes().getString( "(Please enter command)" ) ); m_childDetached = new Checkbox( getRes().getString( "Detached (Professional)" ), false); Panel childPanel = new Panel(); childPanel.setLayout( new BorderLayout() ); childPanel.add( new Label( getRes().getString( "Command: " ) ), BorderLayout.WEST ); childPanel.add( m_childCommand, BorderLayout.CENTER ); childPanel.add( m_childDetached, BorderLayout.EAST ); Panel childPanel2 = new Panel(); childPanel2.setLayout( new BorderLayout() ); childPanel2.add( childPanel, BorderLayout.WEST ); buildCommand( panel, gridBag, c, getRes().getString( "Execute Child Process" ), "child_exec", childPanel2 ); buildCommand( panel, gridBag, c, getRes().getString( "GC" ), "gc", getRes().getString( "Performs a GC sweep." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Is Professional?" ), "is_professional", getRes().getString( "Prints true if this is a Professional Edition." ) ); buildCommand( panel, gridBag, c, getRes().getString( "Is Standard?" ), "is_standard", getRes().getString( "Prints true if this is a Standard Edition." ) ); addWindowListener( this ); } private void buildCommand( Container container, GridBagLayout gridBag, GridBagConstraints c, String label, String command, Object description ) { Button button = new Button( label ); button.setActionCommand( command ); c.fill = GridBagConstraints.BOTH; c.gridwidth = 1; gridBag.setConstraints( button, c ); container.add( button ); button.addActionListener(this); c.gridwidth = GridBagConstraints.REMAINDER; Component desc; if ( description instanceof String ) { desc = new Label( (String)description ); } else if ( description instanceof Component ) { desc = (Component)description; } else { desc = new Label( description.toString() ); } gridBag.setConstraints( desc, c ); container.add( desc ); } /************************************************************************** * ActionListener Methods *************************************************************************/ public void actionPerformed( ActionEvent event ) { String action = event.getActionCommand(); if ( action.equals( "listener" ) ) { // Create the mask. long mask = 0; String[] flags = m_listenerFlags.getSelectedItems(); for ( int i = 0; i < flags.length; i++ ) { String flag = flags[i]; if ( flag.equals( "Service" ) ) { mask |= WrapperEventListener.EVENT_FLAG_SERVICE; } else if ( flag.equals( "Control" ) ) { mask |= WrapperEventListener.EVENT_FLAG_CONTROL; } else if ( flag.equals( "Logging" ) ) { mask |= WrapperEventListener.EVENT_FLAG_LOGGING; } else if ( flag.equals( "Core" ) ) { mask |= WrapperEventListener.EVENT_FLAG_CORE; } } setEventMask( mask ); } int slowSeconds; try { slowSeconds = Integer.parseInt( m_slowSeconds.getText() ); } catch ( NumberFormatException e ) { slowSeconds = 0; } m_slowSeconds.setText( Integer.toString( slowSeconds ) ); setSlowSeconds( slowSeconds ); setServiceName( m_serviceName.getText() ); setConsoleTitle( m_consoleTitle.getText() ); setChildParams( m_childCommand.getText(), m_childDetached.getState() ); Main.this.doAction( action ); } /************************************************************************** * WindowListener Methods *************************************************************************/ public void windowOpened( WindowEvent e ) { } public void windowClosing( WindowEvent e ) { WrapperManager.stopAndReturn( 0 ); } public void windowClosed( WindowEvent e ) { } public void windowIconified( WindowEvent e ) { } public void windowDeiconified( WindowEvent e ) { } public void windowActivated( WindowEvent e ) { } public void windowDeactivated( WindowEvent e ) { } } private class ActionRunner implements Runnable { private String m_action; private boolean m_alive; public ActionRunner(String action) { m_action = action; m_alive = true; } public void run() { // Wait for a second so that the startup will complete. try { Thread.sleep(1000); } catch (InterruptedException e) {} if (!Main.this.doAction(m_action)) { printHelp("\"" + m_action + getRes().getString( "\" is an unknown action." ) ); WrapperManager.stop( 0 ); return; } while (m_alive) { // Idle some try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } } } public void endThread( ) { m_alive = false; } } /*--------------------------------------------------------------- * WrapperListener Methods *-------------------------------------------------------------*/ public Integer start( String[] args ) { String command; System.out.println( getRes().getString( "TestWrapper: start()" ) ); prepareSystemOutErr(); if ( args.length <= 0 ) { System.out.println( getRes().getString( "TestWrapper: An action was not specified. Default to \"dialog\". Use \"help\" for list of actions." ) ); command = "dialog"; } else { command = args[0]; } if ( command.equals( "help" ) ) { printHelp( null ); return null; } try { int port = 9999; m_actionServer = new WrapperActionServer( port ); m_actionServer.enableShutdownAction( true ); m_actionServer.enableHaltExpectedAction( true ); m_actionServer.enableRestartAction( true ); m_actionServer.enableThreadDumpAction( true ); m_actionServer.enableHaltUnexpectedAction( true ); m_actionServer.enableAccessViolationAction( true ); m_actionServer.enableAppearHungAction( true ); m_actionServer.start(); System.out.println( getRes().getString( "TestWrapper: ActionServer Enabled. " ) ); System.out.println( getRes().getString( "TestWrapper: Telnet localhost 9999" ) ); System.out.println( getRes().getString( "TestWrapper: Commands: " ) ); System.out.println( getRes().getString( "TestWrapper: S: Shutdown" ) ); System.out.println( getRes().getString( "TestWrapper: H: Expected Halt" ) ); System.out.println( getRes().getString( "TestWrapper: R: Restart" ) ); System.out.println( getRes().getString( "TestWrapper: D: Thread Dump" ) ); System.out.println( getRes().getString( "TestWrapper: U: Unexpected Halt (Simulate crash)" ) ); System.out.println( getRes().getString( "TestWrapper: V: Access Violation (Actual crash)" ) ); System.out.println( getRes().getString( "TestWrapper: G: Make the JVM appear to be hung." ) ); System.out.println( "TestWrapper:" ); } catch ( java.io.IOException e ) { System.out.println( getRes().getString( "TestWrapper: Unable to open the action server socket: {0}", e.getMessage() ) ); System.out.println( "TestWrapper:" ); m_actionServer = null; System.out.println( "TestWrapper:" ); m_actionServer = null; } if ( command.equals( "dialog" ) ) { System.out.println( getRes().getString( "TestWrapper: Showing dialog..." ) ); try { m_frame = new MainFrame(); m_frame.setVisible( true ); } catch ( java.lang.InternalError e ) { System.out.println( "TestWrapper: " ); System.out.println( getRes().getString( "TestWrapper: ERROR - Unable to display the GUI:" ) ); System.out.println( "TestWrapper: " + e.toString() ); System.out.println( "TestWrapper: " ); System.out.println( getRes().getString( "TestWrapper: Fall back to the \"console\" action." ) ); command = "console"; } catch ( java.awt.AWTError e ) { System.out.println( "TestWrapper: " ); System.out.println( getRes().getString( "TestWrapper: ERROR - Unable to display the GUI:" ) ); System.out.println( "TestWrapper: " + e.toString() ); System.out.println( "TestWrapper: " ); System.out.println( getRes().getString( "TestWrapper: Fall back to the \"console\" action." ) ); command = "console"; } catch ( java.lang.UnsupportedOperationException e ) { // java.awt.HeadlessException does not exist in Java versions prior to 1.4 if ( e.getClass().getName().equals( "java.awt.HeadlessException" ) ) { System.out.println( "TestWrapper: " ); System.out.println( getRes().getString( "TestWrapper: ERROR - Unable to display the GUI:" ) ); System.out.println( "TestWrapper: " + e.toString() ); System.out.println( "TestWrapper: " ); System.out.println( getRes().getString( "TestWrapper: Fall back to the \"console\" action." ) ); command = "console"; } else { throw e; } } } if ( !command.equals( "dialog" ) ) { // * * Start the action thread m_actionRunner = new ActionRunner( command ); Thread actionThread = new Thread( m_actionRunner ); actionThread.start(); } return null; } public int stop( int exitCode ) { System.out.println( getRes().getString( "TestWrapper: stop({0})", new Integer( exitCode ) ) ); if ( m_actionServer != null ) { try { m_actionServer.stop(); } catch ( Exception e ) { System.out.println( getRes().getString( "TestWrapper: Unable to stop the action server: {0}", e.getMessage() ) ); } } if ( m_frame != null ) { if ( !WrapperManager.hasShutdownHookBeenTriggered() ) { m_frame.setVisible( false ); m_frame.dispose(); } m_frame = null; } if ( isNestedExit() ) { System.out.println( getRes().getString( "TestWrapper: calling System.exit({0}) within stop.", String.valueOf(exitCode) ) ); System.exit( exitCode ); } return exitCode; } public void controlEvent( int event ) { System.out.println( getRes().getString( "TestWrapper: controlEvent({0})", new Integer( event ) ) ); if ( event == WrapperManager.WRAPPER_CTRL_LOGOFF_EVENT ) { if ( WrapperManager.isLaunchedAsService() || WrapperManager.isIgnoreUserLogoffs() ) { System.out.println( getRes().getString( "TestWrapper: Ignoring logoff event" ) ); // Ignore } else if ( !ignoreControlEvents() ) { WrapperManager.stop( 0 ); } } else if ( event == WrapperManager.WRAPPER_CTRL_C_EVENT ) { if ( !ignoreControlEvents() ) { //WrapperManager.stop(0); // May be called before the runner is started. if (m_actionRunner != null) { m_actionRunner.endThread(); } } } else { if ( !ignoreControlEvents() ) { WrapperManager.stop( 0 ); } } } /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ /** * Prints the usage text. * * @param error_msg Error message to write with usage text */ private static void printHelp( String errorMsg ) { System.err.println( getRes().getString( "USAGE" ) ); System.err.println( "" ); System.err.println( getRes().getString( "TestWrapper " ) ); printActions(); System.err.println( getRes().getString( " Interactive:" ) ); System.err.println( getRes().getString( " dialog : Shows the dialog interface" ) ); System.err.println( getRes().getString( "[EXAMPLE]" ) ); System.err.println( getRes().getString( " TestAction access_violation_native " ) ); System.err.println( "" ); if ( errorMsg != null ) { System.err.println( getRes().getString( "ERROR: " ) + errorMsg ); System.err.println( "" ); } System.exit( 1 ); } /** * Request the Resources object for this application. */ public static WrapperResources getRes() { if ( m_res == null ) { // Synchronize and then recheck to avoid this method always synchronizing. synchronized( Main.class ) { if ( m_res == null ) { m_res = WrapperManager.loadWrapperResources( "wrapperTestApp", WrapperSystemPropertyUtil.getStringProperty( "wrapper.lang.folder", "../lang" ) ); } } } return m_res; } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ /** * IMPORTANT: Please read the Javadocs for this class at the top of the * page before you start to use this class as a template for integrating * your own application. This will save you a lot of time. */ public static void main( String[] args ) { System.out.println( getRes().getString( "TestWrapper: Initializing..." )); // System.out.println(wrm.getString("test 0 = {0} String = {1} double = {2} object = {3}", new Object[]{ String.valueOf(99), "test",String.valueOf(34.33), "testob"}) ); // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start( new Main(), args ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/Memory.java100644 0 0 13342 12440202301 23475 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; /** * * * @author Leif Mortenson */ public class Memory implements Runnable { private static Memory c_theInstance; private Thread m_runner; /*--------------------------------------------------------------- * Constructor *-------------------------------------------------------------*/ private Memory() { // Start the runner m_runner = new Thread( this, "runner" ); m_runner.start(); } /*--------------------------------------------------------------- * Runnable Method *-------------------------------------------------------------*/ public void run() { long startTime = System.currentTimeMillis(); long lastTest = startTime; try { File file = new File( "../logs/memory.log" ); System.out.println( Main.getRes().getString( "Writing memory Log to: {0}", file ) ); Writer writer = new FileWriter( file ); try { writer.write( Main.getRes().getString( "--> Starting Memory Log\n" ) ); writer.flush(); while( m_runner != null ) { long now = System.currentTimeMillis(); System.out.println( Main.getRes().getString( "Running for {0}ms...", new Long( now - startTime ) ) ); if ( now - lastTest > 15000 ) { Runtime rt = Runtime.getRuntime(); System.gc(); long totalMemory = rt.totalMemory(); long freeMemory = rt.freeMemory(); long usedMemory = totalMemory - freeMemory; writer.write( Main.getRes().getString( "total memory=" ) + pad( totalMemory, 10 ) + Main.getRes().getString( ", used=" ) + pad( usedMemory, 10 ) + Main.getRes().getString( ", free=" ) + pad( freeMemory, 10 ) + "\n" ); writer.flush(); lastTest = now; } try { Thread.sleep( 250 ); } catch ( InterruptedException e ) { } } writer.write( Main.getRes().getString( "<-- Stopping Memory Log\n" ) ); writer.flush(); } finally { writer.close(); } } catch ( IOException e ) { e.printStackTrace(); } } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ private static final String PADDING = " "; private String pad( long n, int len ) { String s = Long.toString( n ); int sLen = s.length(); if ( sLen < len ) { s = s + PADDING.substring( 0, len - sLen ); } return s; } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Memory Tester Running...") ); c_theInstance = new Memory(); // Register a shutdown hook. Runtime.getRuntime().addShutdownHook( new Thread( "shutdown-hook" ) { public void run() { System.out.println(Main.getRes().getString( "Stopping..." ) ); Thread runner = c_theInstance.m_runner; // Tell the main thread to stop. c_theInstance.m_runner = null; // Wait for the thread to actually stop cleanly. try { runner.join(); } catch ( InterruptedException e ) { } System.out.println(Main.getRes().getString( "Stopped." ) ); } } ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/NestedWrapperListener.java100644 0 0 5045 12440202301 26477 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperListener; /** * This is a simple test to see how the WrapperManager behaves when a main * class designed for Integration Method #3 is called using Integration * Method #2. * * @author Leif Mortenson */ public class NestedWrapperListener implements WrapperListener { /************************************************************************** * Constructors *************************************************************************/ private NestedWrapperListener() { System.out.println( "NestedWrapperListener()" ); } /************************************************************************** * WrapperListener Methods *************************************************************************/ public Integer start( String[] args ) { System.out.println( "NestedWrapperListener.start()" ); return null; } public int stop( int exitCode ) { System.out.println( "NestedWrapperListener.stop(" + exitCode + ")" ); return exitCode; } public void controlEvent(int event) { System.out.println( "NestedWrapperListener.controlEvent(" + event + ")" ); } /************************************************************************** * Main Method *************************************************************************/ public static void main( String[] args ) { System.out.println( Main.getRes().getString( "NestedWrapperListener.Initializing..." ) ); System.out.println( Main.getRes().getString("An error saying that the WrapperManager has already been started should be displayed and the JVM will exit." )); // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start( new NestedWrapperListener(), args ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/NoReturn.java100644 0 0 3477 12440202301 23771 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * * * @author Leif Mortenson */ public class NoReturn { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println(Main.getRes().getString( "Main starting loop that will not return" ) ); while(true) { try { Thread.sleep(1000); } catch (InterruptedException e) { } System.out.println(Main.getRes().getString( "NoReturn.main() running...") ); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/OnExit.java100644 0 0 4020 12440202301 23404 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; /** * * * @author Leif Mortenson */ public class OnExit { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Test the handling of on exit handlers." ) ); System.out.println( Main.getRes().getString( "The Wrapper should restart the JVM when it detects and exit code of " ) ); System.out.println( Main.getRes().getString( " 1, 2, or any code except 3. It will then shutdown if it detects " ) ); System.out.println( Main.getRes().getString( " an exit code of 3." ) ); System.out.println(); int exitCode = WrapperManager.getJVMId(); switch ( exitCode ) { case 1: case 2: System.out.println( Main.getRes().getString( "Stopping the JVM with an exit code of {0},\nthe Wrapper should restart.", new Integer( exitCode ) ) ); break; case 3: System.out.println( Main.getRes().getString( "Stopping the JVM with an exit code of {0},\nthe Wrapper should stop.", new Integer( exitCode ) ) ); break; default: System.out.println( Main.getRes().getString( "The Wrapper should have stopped on the previous exitCode 3." ) ); System.out.println( Main.getRes().getString( "We should not be here." ) ); break; } WrapperManager.stop( exitCode ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/OutputLoader.java100644 0 0 5036 12440202301 24635 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import java.io.FileWriter; import java.io.IOException; /** * * * @author Leif Mortenson */ public class OutputLoader { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Start outputting lots of data.") ); long start = System.currentTimeMillis(); int count = 0; while ((System.currentTimeMillis()) < start + 20000) { System.out.println( Main.getRes().getString( "Testing line Out #{0}", new Integer( ++count ) ) ); System.err.println( Main.getRes().getString( "Testing line Err #{0}", new Integer( ++count ) ) ); } System.out.println( Main.getRes().getString( "Printed {0} lines of output in 20 seconds", new Integer( count ) ) ); // Write the output to a file as well, so we can see the results // when output is disabled. try { FileWriter fw = new FileWriter("OutputLoader.log", true); fw.write( Main.getRes().getString( "Printed {0} lines of output in 20 seconds", new Integer( count ) ) ); fw.close(); } catch (IOException e) { e.printStackTrace(); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/PercentOutput.java100644 0 0 3623 12440202301 25027 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * Tests Bug #531880 where % characters in the text output were causing * the wrapper to crash. * * @author Leif Mortenson */ public class PercentOutput { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Starting Test..." ) ); System.out.println( "%"); System.out.println("%%"); System.out.println("%s"); System.out.println("%d"); System.out.println("\\%s%%"); System.out.println( Main.getRes().getString( "Test Complete..." ) ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/Performance.java100644 0 0 14705 12440202301 24472 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * Can be run without the Wrapper as: * java -classpath lib/wrappertest.jar org.tanukisoftware.wrapper.test.Performance * * NOTE - This class intentionally does not use resources for localization because it * needs to be able to be run without the Wrapper components being loaded. * * @author Leif Mortenson */ public class Performance { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ private static void initialize() { System.out.println( "Run some loops for a few seconds to give some time for the JVM to get up and running..." ); long now = System.currentTimeMillis(); long count = 1000000000L; double total = 0; for ( long i = 0; i < count; i++ ) { // Take up some time. double x = 10.5 + i; double y = 3.14159 * i; double z = x * y; total += z; } long time = System.currentTimeMillis() - now; System.out.println( " Complete. Total time=" + ( (double)time / 1000 ) + " seconds. (" + total + ")" ); } private static void dumpThreadGroup( ThreadGroup threadGroup, String indent ) { System.out.println( indent + threadGroup.toString() ); Thread[] threads = new Thread[(int)Math.ceil(threadGroup.activeCount() * 1.2)]; threadGroup.enumerate( threads, false ); System.out.println( indent + "Threads:" ); for ( int i = 0; i < threads.length; i++ ) { if ( threads[i] != null ) { System.out.println( indent + " " + threads[i] ); } } ThreadGroup[] threadGroups = new ThreadGroup[(int)Math.ceil(threadGroup.activeGroupCount() * 1.2)]; threadGroup.enumerate( threadGroups, false ); System.out.println( indent + "Thread Groups:" ); for ( int i = 0; i < threadGroups.length; i++ ) { if ( threadGroups[i] != null ) { dumpThreadGroup( threadGroups[i], indent + " " ); } } } private static void dumpThreadInfo() { Thread thread = Thread.currentThread(); System.out.println( "Thread: " + thread ); /* * Thread.getId() was introduced in 1.5, not available in java 1.4 * System.out.println( " Id: " + thread.getId() ); */ System.out.println( " Name: " + thread.getName() ); System.out.println( " Priority: " + thread.getPriority() ); System.out.println( " ThreadGroup Name: " + thread.getThreadGroup().getName() ); System.out.println( " isDaemon: " + thread.isDaemon() ); System.out.println( "All Threads:" ); ThreadGroup topThreadGroup = thread.getThreadGroup(); while ( topThreadGroup.getParent() != null ) { topThreadGroup = topThreadGroup.getParent(); } dumpThreadGroup( topThreadGroup, " " ); } private static void inMemoryLoopsMath() { System.out.println( "Starting in memory loop test (Math)..." ); long now = System.currentTimeMillis(); long count = 10000000000L; double total = 0; for ( long i = 0; i < count; i++ ) { // Do some math work. double x = 10.5 + i; double y = 3.14159 * i; double z = x * y; total += z; } long time = System.currentTimeMillis() - now; System.out.println( " Complete. Total time=" + ( (double)time / 1000 ) + " seconds. (" + ( (double)time * 1000 / count ) + " usec per cycle.) (" + total + ")" ); } private static void inMemoryLoopsString() { System.out.println( "Starting in memory loop test (Strings)..." ); long now = System.currentTimeMillis(); long count = 100000000L; double total = 0; for ( long i = 0; i < count; i++ ) { // Do some string work. This causes the stack to be used because and is thus slower. String a = "This is a test."; String b = "This is the end."; String c = a + i + b; total += c.length(); } long time = System.currentTimeMillis() - now; System.out.println( " Complete. Total time=" + ( (double)time / 1000 ) + " seconds. (" + ( (double)time * 1000 / count ) + " usec per cycle.) (" + total + ")" ); } public static void main(String[] args) { long now = System.currentTimeMillis(); System.out.println( "This test will run a number of tests to check Java performance. It should be run both with and without the Wrapper." ); String fullVersion = System.getProperty( "java.fullversion" ); String vendor = System.getProperty( "java.vm.vendor", "" ); String os = System.getProperty( "os.name", "" ).toLowerCase(); if ( fullVersion == null ) { fullVersion = System.getProperty( "java.runtime.version" ) + " " + System.getProperty( "java.vm.name" ); } System.out.println( "Java Version: " + fullVersion ); initialize(); dumpThreadInfo(); inMemoryLoopsMath(); inMemoryLoopsString(); Thread runner = new Thread( "runner" ) { public void run() { System.out.println( "Do the same tests in a background thread..." ); dumpThreadInfo(); inMemoryLoopsMath(); inMemoryLoopsString(); System.out.println( "Background thread completed." ); } }; runner.start(); try { runner.join(); } catch ( InterruptedException e ) { } long time = System.currentTimeMillis() - now; System.out.println( "Completed in " + ( (double)time / 1000 ) + " seconds. Exiting." ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/PostShutdownGC.java100644 0 0 4371 12440202301 25102 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * * * @author Leif Mortenson */ public class PostShutdownGC { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( "This application registers a shutdown hook which will run for 15 seconds after the Wrapper has completely shutdown." ); System.out.println( "It will call GC several times to try and completely get rid of the WrapperManager related code." ); // This test intentionally does NOT use any localization to make sure that there is nothing holding the Wrapper related classes in memory. Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { System.out.println( "Starting shutdown hook. Loop for 15 seconds." ); long start = System.currentTimeMillis(); while ( System.currentTimeMillis() - start < 15000 ) { try { Thread.sleep( 1000 ); } catch ( InterruptedException e ) { // Ignore } // Try to prod the garbage collector into collecting unneeded classes and objects. char[] buffer = new char[10 * 1024 * 1024]; buffer = null; System.gc(); } System.out.println( "Shutdown hook complete. Should exit now." ); } } ); System.out.println( "Application complete. Wrapper should stop, invoking the shutdown hooks." ); System.out.println(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/QuickComplete.java100644 0 0 3234 12440202301 24751 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * * * @author Leif Mortenson */ public class QuickComplete { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Quick Complete Running...") ); System.out.println( Main.getRes().getString( "Quick Complete Done...") ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/Restarter.java100644 0 0 13727 12440202301 24207 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperListener; /** * * * @author Leif Mortenson */ public class Restarter implements WrapperListener { /************************************************************************** * Constructors *************************************************************************/ private Restarter() { } /************************************************************************** * WrapperListener Methods *************************************************************************/ public Integer start(String[] args) { System.out.println("start()"); // Start up a thread whose job it is to request a restart in 5 seconds. Thread restarter = new Thread("restarter") { public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) {} // Start up a thread whose only job is to dump output to the console. Thread outputter = new Thread("outputter") { public void run() { int counter = 0; while(true) { /* try { Thread.sleep(50); } catch (InterruptedException e) {} */ Thread.yield(); System.out.println( Main.getRes().getString( " outputer line #{0}", new Integer( ++counter ) ) ); System.out.println( " 1) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 2) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 3) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 4) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 5) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 6) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 7) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 8) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 9) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.println( " 10) " + Main.getRes().getString( "A long line of test data to cause lots of data to be sent to the console." ) ); System.out.flush(); } } }; //outputter.start(); System.out.println(Main.getRes().getString( "Requesting restart..." ) ); WrapperManager.restart(); } }; restarter.start(); return null; } public int stop(int exitCode) { System.out.println( Main.getRes().getString( "stop({0})", new Integer( exitCode ) ) ); return exitCode; } public void controlEvent(int event) { System.out.println( Main.getRes().getString( "controlEvent({0})", new Integer( event ) ) ); if (event == WrapperManager.WRAPPER_CTRL_C_EVENT) { WrapperManager.stop(0); } } /************************************************************************** * Main Method *************************************************************************/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Initializing..." ) ); // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start(new Restarter(), args); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/RuntimeExec.java100644 0 0 74605 12440202301 24466 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperJNIError; import org.tanukisoftware.wrapper.WrapperLicenseError; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperProcess; import org.tanukisoftware.wrapper.WrapperProcessConfig; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.util.Random; /** * * * @author Leif Mortenson */ public class RuntimeExec { private static String c_encoding; /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ static { // In order to read the output from some processes correctly we need to get the correct encoding. // On some systems, the underlying system encoding is different than the file encoding. c_encoding = System.getProperty( "sun.jnu.encoding" ); if ( c_encoding == null ) { c_encoding = System.getProperty( "file.encoding" ); if ( c_encoding == null ) { // Default to Latin1 c_encoding = "Cp1252"; } } } private static void handleInputStream( final InputStream is, final String encoding, final String label ) { Thread runner = new Thread() { public void run() { BufferedReader br; String line; try { br = new BufferedReader( new InputStreamReader( is, encoding ) ); try { while ( ( line = br.readLine() ) != null ) { System.out.println( label + " " + line ); } } finally { br.close(); } } catch ( IOException e ) { e.printStackTrace(); } } }; runner.start(); } private static void handleJavaProcessInner( String testId, Process process ) throws IOException, InterruptedException { try { handleInputStream( process.getInputStream(), c_encoding, testId + "stdout:" ); handleInputStream( process.getErrorStream(), c_encoding, testId + "stderr:" ); } finally { int exitCode = process.waitFor(); System.out.println( Main.getRes().getString( "{0}exitCode: {1}", testId, new Integer( exitCode ) ) ); } } private static void handleJavaProcess( String testId, String command ) throws IOException, InterruptedException { System.out.println( Main.getRes().getString( "{0}Runtime.exec command: {1}", testId, command ) ); handleJavaProcessInner( testId, Runtime.getRuntime().exec( command ) ); } private static void handleJavaProcess( String testId, String[] command ) throws IOException, InterruptedException { System.out.println( Main.getRes().getString( "{0}Runtime.exec command: {1}", testId, toString( command ) ) ); handleJavaProcessInner( testId, Runtime.getRuntime().exec( command ) ); } static final int WAIT_MODE_NONE = 0; static final int WAIT_MODE_API = 1; static final int WAIT_MODE_MANUAL = 2; private static void handleWrapperProcessInner( String testId, WrapperProcess process, long timeoutMS, boolean handleOutErr, boolean closeStdOutErr, boolean closeStdIn, int waitMode ) throws IOException, InterruptedException { try { if ( handleOutErr ) { handleInputStream( process.getStdOut(), c_encoding, testId + "stdout:" ); handleInputStream( process.getStdErr(), c_encoding, testId + "stderr:" ); } else if ( closeStdOutErr ) { process.getStdOut().close(); process.getStdErr().close(); } if ( closeStdIn ) { process.getStdIn().close(); } if ( waitMode == WAIT_MODE_API ) { // We always call waitFor later. } else if ( waitMode == WAIT_MODE_MANUAL ) { if ( timeoutMS > 0 ) { long start = System.currentTimeMillis(); while ( process.isAlive() && ( System.currentTimeMillis() - start < timeoutMS ) ) { try { Thread.sleep( 100 ); } catch ( InterruptedException e ) { } } if ( process.isAlive() ) { System.out.println( Main.getRes().getString( "{0}Timed out waiting for child. Destroying.", testId ) ); process.destroy(); } } } } finally { if ( ( waitMode == WAIT_MODE_API ) || ( waitMode == WAIT_MODE_MANUAL ) ) { int exitCode = process.waitFor(); System.out.println( Main.getRes().getString( "{0}exitCode: {1}", testId, new Integer( exitCode ) ) ); } else { System.out.println( Main.getRes().getString( "{0}leave running...", testId ) ); } } } private static void handleWrapperProcess( String testId, String command, WrapperProcessConfig config, long timeoutMS, boolean handleOutErr, boolean closeStdOutErr, boolean closeStdIn, int waitMode ) throws IOException, InterruptedException { System.out.println( Main.getRes().getString( "{0}WrapperManager.exec command: {1}", testId, command ) ); if ( config == null ) { handleWrapperProcessInner( testId, WrapperManager.exec( command ), timeoutMS, handleOutErr, closeStdOutErr, closeStdIn, waitMode ); } else { handleWrapperProcessInner( testId, WrapperManager.exec( command, config ), timeoutMS, handleOutErr, closeStdOutErr, closeStdIn, waitMode ); } } private static void handleWrapperProcess( String testId, String command ) throws IOException, InterruptedException { handleWrapperProcess( testId, command, null, 0, true, false, false, WAIT_MODE_MANUAL ); } private static void handleWrapperProcess( String testId, String[] command, WrapperProcessConfig config, long timeoutMS, boolean handleOutErr, boolean closeStdOutErr, boolean closeStdIn, int waitMode ) throws IOException, InterruptedException { System.out.println( Main.getRes().getString( "{0}WrapperManager.exec command: {1}", testId, toString( command ) ) ); if ( config == null ) { handleWrapperProcessInner( testId, WrapperManager.exec( command ), timeoutMS, handleOutErr, closeStdOutErr, closeStdIn, waitMode ); } else { handleWrapperProcessInner( testId, WrapperManager.exec( command, config ), timeoutMS, handleOutErr, closeStdOutErr, closeStdIn, waitMode ); } } private static void handleWrapperProcess( String testId, String[] command ) throws IOException, InterruptedException { handleWrapperProcess( testId, command, null, 0, true, false, false, WAIT_MODE_MANUAL ); } private static void beginCase( String testId ) { System.out.println(); System.out.println( Main.getRes().getString( "{0}BEGIN ----------------------------------------", testId ) ); } private static void endCase( String testId ) { // Try to keep all output form the test within the the BEGIN/END block. try { Thread.sleep( 1000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "{0}END ----------------------------------------", testId ) ); } private static String toString( String[] command ) { StringBuffer sb = new StringBuffer(); sb.append( "{" ); for ( int i = 0; i < command.length; i++ ) { String arg = command[i]; if ( i > 0 ) { sb.append( ", " ); } sb.append( "\"" ); sb.append( arg ); sb.append( "\"" ); } sb.append( "}" ); return sb.toString(); } private static void caseSimpleTestJava( final String simplewaiter ) { String testId = "Simple Java : "; beginCase( testId ); try { try { String command = simplewaiter + " -v \"test 123\" test 123 \"\\\"test\\\""; handleJavaProcess( testId, command ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseSimpleTestWrapper( final String simplewaiter ) { String testId = "Simple Wrapper : "; beginCase( testId ); try { try { String command = simplewaiter + " -v \"test 123\" test 123 \"\\\"test\\\""; handleWrapperProcess( testId, command ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseSimpleTestJavaAry( final String simplewaiter ) { String testId = "Simple Java (Array) : "; beginCase( testId ); try { try { String[] command = { simplewaiter, "-v", "\"test 123\"", "test 123", "\"\\\"test\\\"\"" }; handleJavaProcess( testId, command ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseSimpleTestWrapperAry( final String simplewaiter ) { String testId = "Simple Wrapper (Array) : "; beginCase( testId ); try { try { String[] command = { simplewaiter, "-v", "\"test 123\"", "test 123", "\"\\\"test\\\"\"" }; handleWrapperProcess( testId, command ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseLongCommand( final String simplewaiter, int len, boolean expectFailure ) { String testId = "Long Command " + len + ": "; beginCase( testId ); try { try { StringBuffer sb = new StringBuffer(); sb.append( simplewaiter ); sb.append( " -v " ); while ( sb.length() < len - 1 ) { sb.append( "x" ); } // Make the last character a y so we can verify that it is included correctly. sb.append( "y" ); String command = sb.toString(); handleWrapperProcess( testId, command ); if ( expectFailure ) { System.out.println( Main.getRes().getString( "{0}Did not fail as expected.", testId ) ); } } catch ( Exception e ) { if ( expectFailure ) { System.out.println( Main.getRes().getString( "{0}Failed as expected: {1}", testId, e.toString() ) ); } else { e.printStackTrace(); } } } finally { endCase( testId ); } } private static void caseWaitFor( final String simplewaiter ) { String testId = "WaitFor : "; beginCase( testId ); try { try { String command = simplewaiter + " 1 10"; handleWrapperProcess( testId, command, null, 0, true, false, false, WAIT_MODE_API ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseSmallChildProcess( final String simplewaiter ) { String testId = "Simple Wrapper (Array) : "; beginCase( testId ); try { try { String command = simplewaiter + " 65 1"; handleWrapperProcess( testId, command, null, 0, false, false, true, WAIT_MODE_MANUAL ); } catch ( InterruptedException e ) { e.printStackTrace(); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseVFork( final String simplewaiter ) { String testId = "VFork : "; beginCase( testId ); try { if ( !WrapperProcessConfig.isSupported( WrapperProcessConfig.VFORK_EXEC ) ) { System.out.println( Main.getRes().getString( "{0}vfork not supported", testId ) ); } else { System.out.println( Main.getRes().getString( "{0}vfork is supported", testId ) ); try { String command = simplewaiter + " 20 10"; handleWrapperProcess( testId, command, new WrapperProcessConfig().setStartType( WrapperProcessConfig.VFORK_EXEC ), 0, true, false, false, WAIT_MODE_MANUAL ); } catch ( Exception e ) { e.printStackTrace(); } } } finally { endCase( testId ); } } private static void casePosixSpawn( final String simplewaiter ) { String testId = "PosixSpawn : "; beginCase( testId ); try { if ( !WrapperProcessConfig.isSupported( WrapperProcessConfig.POSIX_SPAWN ) ) { System.out.println( Main.getRes().getString( "{0}posix spawn not supported", testId ) ); } else { System.out.println( Main.getRes().getString( "{0}posix spawn is supported", testId ) ); try { String command = simplewaiter + " 20 10"; handleWrapperProcess( testId, command, new WrapperProcessConfig().setStartType( WrapperProcessConfig.POSIX_SPAWN ), 0, true, false, false, WAIT_MODE_MANUAL ); } catch ( Exception e ) { e.printStackTrace(); } } } finally { endCase( testId ); } } private static void caseEnvSmall( final String simplewaiter ) { String testId = "Environment Small : "; beginCase( testId ); try { try { WrapperProcessConfig config = new WrapperProcessConfig(); java.util.Map environment = config.getEnvironment(); environment.clear(); environment.put( "TEST", "TEST123" ); System.out.println( Main.getRes().getString( "{0}size of Environment map = {1}", testId, new Integer( environment.size() ) ) ); String command = simplewaiter + " -e TEST"; handleWrapperProcess( testId, command, config, 0, true, false, false, WAIT_MODE_MANUAL ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseEnvLarge( final String simplewaiter, int len, boolean expectFailure ) { String testId = "Environment Large " + len + ": "; beginCase( testId ); try { try { int valueLen = len - 4 - 1; // "TEST=" StringBuffer sb = new StringBuffer(); for ( int i = 0; i < valueLen - 1; i++ ) { sb.append( "X" ); } sb.append( "Y" ); // Make it so we can see the last value. String value = sb.toString(); WrapperProcessConfig config = new WrapperProcessConfig(); java.util.Map environment = config.getEnvironment(); environment.clear(); environment.put( "TEST", value ); System.out.println( Main.getRes().getString( "{0}size of Environment map = {1}", testId, new Integer( environment.size() ) ) ); String command = simplewaiter + " -e TEST"; handleWrapperProcess( testId, command, config, 0, true, false, false, WAIT_MODE_MANUAL ); if ( expectFailure ) { System.out.println( Main.getRes().getString( "{0}Did not fail as expected.", testId ) ); } } catch ( Exception e ) { if ( expectFailure ) { System.out.println( Main.getRes().getString( "{0}Failed as expected: {1}", testId, e.toString() ) ); } else { e.printStackTrace(); } } } finally { endCase( testId ); } } private static void caseWorkingDir( final String simplewaiter ) { String testId = "Change Working Dir : "; beginCase( testId ); try { if ( WrapperProcessConfig.isSupported( WrapperProcessConfig.FORK_EXEC ) || WrapperProcessConfig.isSupported( WrapperProcessConfig.VFORK_EXEC ) ) { System.out.println( Main.getRes().getString( "{0}changing the working directory is supported", testId ) ); try { WrapperProcessConfig config = new WrapperProcessConfig(); config.setStartType( WrapperProcessConfig.isSupported( WrapperProcessConfig.FORK_EXEC ) ? WrapperProcessConfig.FORK_EXEC : WrapperProcessConfig.VFORK_EXEC ); config.setWorkingDirectory( new File("..") ); String command; if ( WrapperManager.isWindows() ) { command = "cmd.exe /c dir"; } else { command = "ls -l"; } handleWrapperProcess( testId, command, config, 0, true, false, false, WAIT_MODE_MANUAL ); } catch ( Exception e ) { e.printStackTrace(); } } else { System.out.println( Main.getRes().getString( "{0}changing the working directory is not supported", testId ) ); } } finally { endCase( testId ); } } /** * Test a short WrapperManager.exec process whose entire lifespan is while another Runtime.exec process is running. */ private static void caseWrapperDuringJava( final String simplewaiter ) { String testId = "Wrapper During Java : "; beginCase( testId ); try { try { String javaCommand = simplewaiter + " 5 10"; String wrapperCommand = simplewaiter + " 6 5"; Process javaProcess = Runtime.getRuntime().exec( javaCommand ); handleInputStream( javaProcess.getInputStream(), c_encoding, testId + "Runtime.exec stdout:" ); handleInputStream( javaProcess.getErrorStream(), c_encoding, testId + "Runtime.exec stderr:" ); WrapperProcess wrapperProcess = WrapperManager.exec( wrapperCommand ); handleInputStream( wrapperProcess.getStdOut(), c_encoding, testId + "WrapperManager.exec stdout:" ); handleInputStream( wrapperProcess.getStdErr(), c_encoding, testId + "WrapperManager.exec stderr:" ); System.out.println( Main.getRes().getString( "{0}WrapperManager.exec exitCode: {1}", testId, new Integer( wrapperProcess.waitFor() ) ) ); System.out.println( Main.getRes().getString( "{0}Runtime.exec exitCode: {1}", testId, new Integer( javaProcess.waitFor() ) ) ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } /** * Test a short Runtime.exec process whose entire lifespan is while another WrapperManager.exec process is running. */ private static void caseJavaDuringWrapper( final String simplewaiter ) { String testId = "Java During Wrapper : "; beginCase( testId ); try { try { String wrapperCommand = simplewaiter + " 5 10"; String javaCommand = simplewaiter + " 6 5"; WrapperProcess wrapperProcess = WrapperManager.exec( wrapperCommand ); handleInputStream( wrapperProcess.getStdOut(), c_encoding, testId + "WrapperManager.exec stdout:" ); handleInputStream( wrapperProcess.getStdErr(), c_encoding, testId + "WrapperManager.exec stderr:" ); Process javaProcess = Runtime.getRuntime().exec( javaCommand ); handleInputStream( javaProcess.getInputStream(), c_encoding, testId + "Runtime.exec stdout:" ); handleInputStream( javaProcess.getErrorStream(), c_encoding, testId + "Runtime.exec stderr:" ); System.out.println( Main.getRes().getString( "{0}Runtime.exec exitCode: {1}", testId, new Integer( javaProcess.waitFor() ) ) ); System.out.println( Main.getRes().getString( "{0}WrapperManager.exec exitCode: {1}", testId, new Integer( wrapperProcess.waitFor() ) ) ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseInvalid( final String simplewaiter ) { String testId = "Invalid : "; beginCase( testId ); try { try { String command = "invalid"; handleWrapperProcess( testId, command, null, 0, true, false, false, WAIT_MODE_MANUAL ); System.out.println( Main.getRes().getString( "{0}ERROR! Did not fail as expected.", testId ) ); } catch ( Exception e ) { System.out.println( Main.getRes().getString( "{0}Failed as expected.", testId ) ); } } finally { endCase( testId ); } } private static void caseTimeoutShort( final String simplewaiter ) { String testId = "Timeout Short : "; beginCase( testId ); try { try { String command = simplewaiter + " 0 5"; handleWrapperProcess( testId, command, null, 10000, true, false, false, WAIT_MODE_MANUAL ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static void caseTimeoutLong( final String simplewaiter ) { String testId = "Timeout Long : "; beginCase( testId ); try { try { String command = simplewaiter + " 0 30"; handleWrapperProcess( testId, command, null, 10000, true, false, false, WAIT_MODE_MANUAL ); } catch ( Exception e ) { e.printStackTrace(); } } finally { endCase( testId ); } } private static boolean caseLeaveRunning( final String simplewaiter ) { String testId = "Leave Running : "; beginCase( testId ); try { try { String command = simplewaiter + " 1 600"; handleWrapperProcess( testId, command, null, 0, true, false, false, WAIT_MODE_NONE ); return false; } catch ( WrapperJNIError e ) { System.out.println( Main.getRes().getString( "{0}Unable to launch child process because JNI library unavailable. Normal on shutdown.", testId ) ); return true; } catch ( Exception e ) { e.printStackTrace(); return true; } } finally { endCase( testId ); } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { final String simplewaiter; if ( WrapperManager.isWindows() ) { simplewaiter = "../test/simplewaiter.exe"; } else { simplewaiter = "../test/simplewaiter"; } System.out.println( "Communicate with child processes using encoding: " + c_encoding ); Random rand = new Random(); System.out.println( Main.getRes().getString( "Is DYNAMIC supported? A:" ) + WrapperProcessConfig.isSupported( WrapperProcessConfig.DYNAMIC ) ); System.out.println( Main.getRes().getString( "Is FORK_EXEC supported? A:" ) + WrapperProcessConfig.isSupported( WrapperProcessConfig.FORK_EXEC ) ); System.out.println( Main.getRes().getString( "Is VFORK_EXEC supported? A:" ) + WrapperProcessConfig.isSupported( WrapperProcessConfig.VFORK_EXEC ) ); System.out.println( Main.getRes().getString( "Is POSIX_SPAWN supported? A:" ) + WrapperProcessConfig.isSupported( WrapperProcessConfig.POSIX_SPAWN ) ); caseSimpleTestJava( simplewaiter ); caseSimpleTestWrapper( simplewaiter ); caseSimpleTestJavaAry( simplewaiter ); caseSimpleTestWrapperAry( simplewaiter ); caseLongCommand( simplewaiter, 32766, false ); caseLongCommand( simplewaiter, 32767, true ); caseWaitFor( simplewaiter ); caseSmallChildProcess( simplewaiter ); caseVFork( simplewaiter ); casePosixSpawn( simplewaiter ); caseEnvSmall( simplewaiter ); caseEnvLarge( simplewaiter, 32767, false ); caseEnvLarge( simplewaiter, 32768, true ); caseWorkingDir( simplewaiter ); caseWrapperDuringJava( simplewaiter ); caseJavaDuringWrapper( simplewaiter ); caseInvalid( simplewaiter ); caseTimeoutShort( simplewaiter ); caseTimeoutLong( simplewaiter ); // This test should be the last as it relies on the Wrapper shutting it down. caseLeaveRunning( simplewaiter ); System.out.println(); if ( WrapperManager.getJVMId() == 1 ) { // First invocation. System.out.println( Main.getRes().getString( "All Done. Restarting..." ) ); WrapperManager.restart(); } else { // Second invocation. // Register a long shutdownhook which will cause the Wrapper to timeout and kill the JVM. System.out.println( Main.getRes().getString( "All Done. Registering long shutdown hook and stopping.\nWrapper should timeout and kill the JVM, cleaning up all processes in the process." ) ); Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { System.out.println( Main.getRes().getString( "Starting shutdown hook. Loop for 25 seconds.") ); System.out.println( Main.getRes().getString( "Should timeout unless this property is set: wrapper.jvm_exit.timeout=30" ) ); long start = System.currentTimeMillis(); boolean failed = false; while ( System.currentTimeMillis() - start < 25000 ) { if ( !failed ) { failed = caseLeaveRunning( simplewaiter ); System.out.println( Main.getRes().getString( "Launched child...") ); } try { Thread.sleep( 250 ); } catch ( InterruptedException e ) { // Ignore } } System.out.println( Main.getRes().getString( "Shutdown hook complete. Should exit now." ) ); } } ); System.exit( 0 ); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/ShutdownHook.java100644 0 0 6651 12440202301 24646 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html * * * Portions of the Software have been derived from source code * developed by Silver Egg Technology under the following license: * * Copyright (c) 2001 Silver Egg Technology * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sub-license, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. */ /** * * * @author Leif Mortenson */ public class ShutdownHook { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "This application registers a shutdown hook which") ); System.out.println( Main.getRes().getString( "should be executed after the JVM has told the Wrapper") ); System.out.println( Main.getRes().getString( "it is exiting." ) ); System.out.println( Main.getRes().getString( "This is to test the wrapper.jvm_exit.timeout property" ) ); Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { System.out.println( Main.getRes().getString( "Starting shutdown hook. Loop for 25 seconds.") ); System.out.println( Main.getRes().getString( "Should timeout unless this property is set: wrapper.jvm_exit.timeout=30" ) ); long start = System.currentTimeMillis(); while ( System.currentTimeMillis() - start < 25000 ) { try { Thread.sleep( 250 ); } catch ( InterruptedException e ) { // Ignore } } System.out.println( Main.getRes().getString( "Shutdown hook complete. Should exit now." ) ); // Run GC to invoke finalize on unsed objects to test the shutdown process. System.out.println( "GC BEGIN" ); System.gc(); System.out.println( "GC END" ); try { Thread.sleep( 2000 ); } catch ( InterruptedException e ) { // Ignore } System.out.println( "DONE" ); } } ); System.out.println( Main.getRes().getString( "Application complete. Wrapper should stop, invoking the shutdown hooks." ) ); System.out.println(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/ShutdownLock.java100644 0 0 4656 12440202301 24641 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperShuttingDownException; /** * * * @author Leif Mortenson */ public class ShutdownLock { /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { Thread daemon = new Thread() { public void run() { System.out.println( Main.getRes().getString( "Daemon thread started." ) ); System.out.println( Main.getRes().getString( "Requesting a shutdown lock." ) ); try { WrapperManager.requestShutdownLock(); } catch ( WrapperShuttingDownException e ) { System.out.println( e ); } System.out.println( Main.getRes().getString( "Waiting for 20 seconds." ) ); try { Thread.sleep( 20000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Freeing up shutdown lock." ) ); WrapperManager.releaseShutdownLock(); System.out.println( Main.getRes().getString( "Daemon thread completed." ) ); } }; daemon.setDaemon( true ); System.out.println( Main.getRes().getString( "Starting daemon thread." ) ); daemon.start(); try { Thread.sleep( 5000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Application complete. Wrapper should stop when shutdown lock is released.") ); System.out.println(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/SimpleWrapperListener.java100644 0 0 4640 12440202301 26506 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperListener; /** * This is a very simple test of how a main class using Integration Method #3 * works. * * @author Leif Mortenson */ public class SimpleWrapperListener implements WrapperListener { /************************************************************************** * Constructors *************************************************************************/ private SimpleWrapperListener() { System.out.println( "SimpleWrapperListener()" ); } /************************************************************************** * WrapperListener Methods *************************************************************************/ public Integer start( String[] args ) { System.out.println( "SimpleWrapperListener.start()" ); return null; } public int stop( int exitCode ) { System.out.println( "SimpleWrapperListener.stop(" + exitCode + ")" ); return exitCode; } public void controlEvent(int event) { System.out.println( "SimpleWrapperListener.controlEvent(" + event + ")" ); } /************************************************************************** * Main Method *************************************************************************/ public static void main( String[] args ) { System.out.println( Main.getRes().getString( "SimpleWrapperListener.Initializing..." ) ); System.out.println( Main.getRes().getString( "This test should simply 'start()' and 'stop()'." ) ); // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start( new SimpleWrapperListener(), args ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/SlowStop.java100644 0 0 5161 12440202301 23777 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperListener; /** * This test is to make sure the Wrapper handles applications whose stop method * take too much time to complete. * * @author Leif Mortenson */ public class SlowStop implements WrapperListener { /************************************************************************** * Constructors *************************************************************************/ private SlowStop() { } /************************************************************************** * WrapperListener Methods *************************************************************************/ public Integer start( String[] args ) { System.out.println( "start()" ); return null; } public int stop( int exitCode ) { System.out.println( "stop(" + exitCode + ")" ); System.out.println( Main.getRes().getString( "This stop method will wait for 45 seconds before continuing." ) ); System.out.println( Main.getRes().getString( "The Wrapper will timeout unless wrapper.shutdown.timeout is set to a larger value." ) ); try { Thread.sleep( 45000 ); } catch ( InterruptedException e ) { } System.out.println( Main.getRes().getString( "Stop complete." ) ); return exitCode; } public void controlEvent( int event ) { System.out.println( "controlEvent(" + event + ")" ); } /************************************************************************** * Main Method *************************************************************************/ public static void main( String[] args ) { System.out.println( Main.getRes().getString( "Initializing..." ) ); // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start( new SlowStop(), args ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/StopWhileStarting.java100644 0 0 6535 12440202301 25645 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import org.tanukisoftware.wrapper.WrapperManager; import org.tanukisoftware.wrapper.WrapperListener; /** * This test is to make sure the Wrapper works correctly when stop or restart is * called before the start method has completed. * * @author Leif Mortenson */ public class StopWhileStarting implements WrapperListener { /************************************************************************** * Constructors *************************************************************************/ private StopWhileStarting() { } /************************************************************************** * WrapperListener Methods *************************************************************************/ public Integer start(String[] args) { System.out.println("start()"); switch ( WrapperManager.getJVMId() ) { case 1: System.out.println( Main.getRes().getString( "start() request restart" ) ); WrapperManager.restart(); break; case 2: System.out.println( Main.getRes().getString( "start() request halt(0)" ) ); Runtime.getRuntime().halt( 0 ); break; case 3: System.out.println( Main.getRes().getString( "start() request System.exit(99). Will restart due to on_exit configuration" ) ); System.exit( 99 ); break; case 4: System.out.println( Main.getRes().getString( "start() returns exit code 99. Will restart due to on_exit configuration" ) ); return new Integer( 99 ); default: System.out.println( Main.getRes().getString( "start() request stop(0)") ); WrapperManager.stop( 0 ); break; } System.out.println( Main.getRes().getString( "start() END - Should not get here.") ); return null; } public int stop(int exitCode) { System.out.println("stop(" + exitCode + ")"); return exitCode; } public void controlEvent(int event) { System.out.println("controlEvent(" + event + ")"); if (event == WrapperManager.WRAPPER_CTRL_C_EVENT) { WrapperManager.stop(0); } } /************************************************************************** * Main Method *************************************************************************/ public static void main(String[] args) { System.out.println( Main.getRes().getString( "Initializing..." ) ); // Start the application. If the JVM was launched from the native // Wrapper then the application will wait for the native Wrapper to // call the application's start method. Otherwise the start method // will be called immediately. WrapperManager.start(new StopWhileStarting(), args); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/SystemProperty.java100644 0 0 3762 12440202301 25243 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ /** * This test is to make sure that property values set in the wrapper config file * are handled and passed into the JVM as expected. * * @author Leif Mortenson */ public class SystemProperty { private static int m_exitCode = 0; /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main( String[] args ) { testProperty( "VAR1", "abc" ); testProperty( "VAR2", "\\" ); testProperty( "VAR3", "\"" ); testProperty( "VAR4", "abc" ); testProperty( "VAR5", "\\" ); testProperty( "VAR6", "\\\\" ); testProperty( "VAR7", "\"" ); System.out.println( Main.getRes().getString( "Main complete.") ); System.exit( m_exitCode ); } private static void testProperty( String name, String expectedValue ) { System.out.println( Main.getRes().getString( "Testing system property: {0}", name ) ); System.out.println( Main.getRes().getString( " Expected:{0}", expectedValue ) ); String value = System.getProperty( name ); System.out.println( Main.getRes().getString( " Value :{0}", value ) ); if ( expectedValue.equals( value ) ) { System.out.println( Main.getRes().getString( " OK" ) ); } else { System.out.println( Main.getRes().getString( " FAILED!!!" ) ); m_exitCode = 1; } System.out.println(); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/TestUtils.java100644 0 0 15376 12440202301 24176 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import org.tanukisoftware.wrapper.WrapperPropertyUtil; /** * This test is designed to make sure the Wrapper handles the case where the * JVM is restarted while the Wrapper is blocking due to a long disk IO queue. * Prior to 3.5.11, the Wrapper would sometimes exit before it noticed that * the JVM had wanted to restart. * * @author Leif Mortenson */ public class TestUtils { /*--------------------------------------------------------------- * Constructors *-------------------------------------------------------------*/ private TestUtils() { } /*--------------------------------------------------------------- * Static Methods *-------------------------------------------------------------*/ /** * Sleep for the specified time without any exceptions. * * @param ms Time to sleep. */ public static void sleep( long ms ) { try { Thread.sleep( ms ); } catch ( InterruptedException e ) { } } /** * Writes the specified text to a file. This method is not an efficient * way to write multiple lines of text as the file is opened and closed * each time this is called. It can be useful when it is necessary to * quickly write out some text however. * * @param file File to be written to. * @param text Text to be written to the file. May contain multiple lines. * No additional line feeds will be written out so it is * important to include them if needed. * @param encoding Encoding to use when writing the text. Null implies * that the system default will be used. * @param append If true and the file already exists then the text will be * appended to the end of the file. If false then a new file * will always be created. * * @throws IOException If there are any problems writing to the file. */ public static void writeTextFile( File file, String text, String encoding, boolean append ) throws IOException { OutputStream fos = new FileOutputStream( file, append ); try { Writer osw; if ( encoding == null ) { osw = new OutputStreamWriter( fos ); } else { osw = new OutputStreamWriter( fos, encoding ); } BufferedWriter writer = new BufferedWriter( osw ); try { writer.write( text ); } finally { writer.close(); } } finally { fos.close(); } } /** * Writes the specified text to a file. * * @param file File to be written to. * @param text Text to be written to the file. May contain multiple lines. * No additional line feeds will be written out so it is * important to include them if needed. * * @throws IOException If there are any problems writing to the file. */ public static void writeTextFile( File file, String text ) throws IOException { writeTextFile( file, text, "UTF-8", false ); } /** * Writes a command to the Wrapper command file. * * If the file already exists then a warning will be logged as the file will * be overwritten. The Wrapper polls for the file at regular intervals and * this can happen if two command are written in rapid succession. If two * commands must be written then they should be written to the same file at * the same time to avoid any synchronization problems between the Wrapper * and this process. * * @param command Command to write to the configured Wrapper command file. * * @throws IOException If there are any problems writing to the file. * @throws IllegalStateException If the wrapper.commandfile property has not * been defined. */ public static void writeWrapperCommand( String command ) throws IOException, IllegalStateException { String commandFilename = WrapperPropertyUtil.getStringProperty( "wrapper.commandfile", null ); if ( commandFilename == null ) { throw new IllegalStateException( "The wrapper.commandfile property has not been configured." ); } File commandFile = new File( commandFilename ); if ( commandFile.exists() ) { System.out.println( Main.getRes().getString( "WARNING - Command file already exists when trying to write a new command: {0}", commandFile.toString() ) ); } writeTextFile( commandFile, command ); } /** * Writes a test command to the Wrapper command file. * * If the file already exists then a warning will be logged as the file will * be overwritten. The Wrapper polls for the file at regular intervals and * this can happen if two command are written in rapid succession. If two * commands must be written then they should be written to the same file at * the same time to avoid any synchronization problems between the Wrapper * and this process. * * @param command Command to write to the configured Wrapper command file. * * @throws IOException If there are any problems writing to the file. * @throws IllegalStateException If the wrapper.commandfile property has not * been defined or the wrapper.command.enable_tests * property has not been set to true. */ public static void writeWrapperTestCommand( String command ) throws IOException, IllegalStateException { boolean enableTests = WrapperPropertyUtil.getBooleanProperty( "wrapper.commandfile.enable_tests", false ); if ( !enableTests ) { throw new IllegalStateException( "The wrapper.command.enable_tests property has not been set to true." ); } writeWrapperCommand( command ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/TimedLogOutput.java100644 0 0 6513 12440202301 25134 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.util.Random; /** * * * @author Leif Mortenson */ public class TimedLogOutput { /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ private static String lPad( int n, int len, String padding ) { String s = Integer.toString( n ); int len2 = s.length(); if ( len2 < len ) { return padding.substring( 0, len - len2 ) + s; } else { return s; } } /*--------------------------------------------------------------- * Main Method *-------------------------------------------------------------*/ public static void main(String[] args) { // This class is not localized so we can run it without the Wrapper code. System.out.println( "Log lots of output of varying length with varying delays between entries. Each line shows the time it took to log the previous entry. This is done in a repeatable random series." ); // Build up a long base string. We will be sending varying substring instances of this to the output. StringBuffer messageSB = new StringBuffer(); for ( int i = 0; i < 1000; i++ ) { messageSB.append( "ThisIsAVeryLongStringWithoutSpaces." ); // 35 chars } String message = messageSB.toString(); // 35000 chars. int messageLen = message.length(); // Always seed the random generator so we get the same results for every run. Random rand = new Random( 0 ); long allStart = System.currentTimeMillis(); System.out.println( "Starting..." ); long prevTime = 0; for ( int i = 0; i < 1000; i++ ) { int subMessageLen = (int)( rand.nextFloat() * (messageLen - 1) ); String subMessage = message.substring( 0, subMessageLen ); String line = "#" + lPad( i, 6, "0000000000" ) + ":" + lPad( (int)prevTime, 6, " " ) + "ms:" + lPad( subMessageLen, 6, " " ) + ":" + subMessage; long lineStart = System.currentTimeMillis(); System.out.println( line ); long lineTime = System.currentTimeMillis() - lineStart; prevTime = lineTime; // Only sleep on 10% of the lines, then on those do a random lengthed sleep. if ( rand.nextFloat() < 0.10f ) { long sleepTime = (long)( rand.nextFloat() * 50 ); try { Thread.sleep( sleepTime ); } catch ( InterruptedException e ) { } } } long allTime = System.currentTimeMillis() - allStart; System.out.println( "Total time: " + allTime ); System.out.println( "All done." ); } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/WrapperPrintArgs.java100644 0 0 1374 12440202301 25461 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2012 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ public class WrapperPrintArgs { public static void main( String[] args ) { System.out.println( "Dump all Application Arguments:" ); System.out.println( " argv=" + args.length ); for ( int i = 0; i < args.length; i++ ) { System.out.println( " args[" + i + "]=" + args[i] ); } } } wrapper_3.5.26_src/src/java/org/tanukisoftware/wrapper/test/WrapperPrintParam.java100644 0 0 7073 12440202301 25627 0ustar 0 0 package org.tanukisoftware.wrapper.test; /* * Copyright (c) 1999, 2012 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the proprietary information of Tanuki Software. * You shall use it only in accordance with the terms of the * license agreement you entered into with Tanuki Software. * http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html */ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import java.util.ListIterator; import java.util.Arrays; public class WrapperPrintParam { public static void main( String[] args ) { System.out.println( "Dump all JVM parameters using RuntimeMXBean:" ); System.out.println( " (There is a bug in Java that was fixed in 1.7 which causes all parameters being displayed below to be split into different arguments when spaces are encountered.)" ); try { Class cRuntimeMXBean = Class.forName( "java.lang.management.RuntimeMXBean" ); Class cManagementFactory = Class.forName( "java.lang.management.ManagementFactory" ); Method mGetRuntimeMXBean = cManagementFactory.getMethod( "getRuntimeMXBean", null ); Method mGetInputArguments = cRuntimeMXBean.getMethod( "getInputArguments", null ); Object runtimemxBean = mGetRuntimeMXBean.invoke( null, ( Object[] ) null ); List jvm_args = ( List ) mGetInputArguments.invoke( runtimemxBean, ( Object[] ) null ); System.out.println( jvm_args.size() + " JVM Parameter(s):" ); for ( ListIterator i = jvm_args.listIterator(); i.hasNext(); ) { String arg = (String)i.next(); System.out.println( " " + arg ); } List app_args = Arrays.asList( args ); System.out.println( app_args.size() + " Application Parameter(s):" ); for ( ListIterator i = app_args.listIterator(); i.hasNext(); ) { String arg = ( String ) i.next(); System.out.println( " " + arg ); } System.out.println(); System.out.println( "Resulting System Properties:" ); for ( ListIterator i = jvm_args.listIterator(); i.hasNext(); ) { String arg = (String)i.next(); if ( arg.startsWith( "-D" ) ) { int pos = arg.indexOf( '=' ); if ( pos >= 0 ) { String name = arg.substring( 2, pos ); System.out.println( " " + name + "=" + System.getProperty( name ) ); } } } } catch ( ClassNotFoundException e ) { e.printStackTrace(); } catch ( IllegalArgumentException e ) { e.printStackTrace(); } catch ( IllegalAccessException e ) { e.printStackTrace(); } catch ( InvocationTargetException e ) { e.printStackTrace(); } catch ( SecurityException e ) { e.printStackTrace(); } catch ( NoSuchMethodException e ) { e.printStackTrace(); } } } wrapper_3.5.26_src/src/test/org/tanukisoftware/wrapper/WrapperManagerSystemTimeTestCase.java100644 0 0 11115 12440202301 27673 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the confidential and proprietary information * of Tanuki Software. ("Confidential Information"). You shall * not disclose such Confidential Information and shall use it * only in accordance with the terms of the license agreement you * entered into with Tanuki Software. */ import junit.framework.TestCase; /** * Tests the conversion of system time into ticks. * * @author Leif Mortenson */ public class WrapperManagerSystemTimeTestCase extends TestCase { private final int TICK_MS = 100; /*--------------------------------------------------------------- * Constructor *-------------------------------------------------------------*/ public WrapperManagerSystemTimeTestCase( String name ) { super( name ); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ private int getSystemTicks( long time ) { // Calculate a tick count using the current system time. The // conversion from a long in ms, to an int in TICK_MS increments // will result in data loss, but the loss of bits and resulting // overflow is expected and Ok. return (int)( time / TICK_MS ); } private long getTickAge( int start, int end ) { // Important to cast the first value so that negative values are correctly // cast to negative long values. return (long)( end - start ) * TICK_MS; } public void doTest( long time, int expectedTicks, int negTicks, int posTicks ) { int ticks = getSystemTicks( time ); assertEquals( "getSystemTicks( " + time + " ) failed", expectedTicks, ticks ); long posAge = getTickAge( posTicks, expectedTicks ); assertEquals( "getTickAge( " + posTicks + ", " + expectedTicks + " )", 1000L, posAge ); long negAge = getTickAge( negTicks, expectedTicks ); assertEquals( "getTickAge( " + negTicks + ", " + expectedTicks + " )", -1000L, negAge ); } /*--------------------------------------------------------------- * Test Cases *-------------------------------------------------------------*/ public void testSimple() { doTest( 0L, 0, 10, -10 ); doTest( 1L, 0, 10, -10 ); doTest( 2L, 0, 10, -10 ); doTest( 99L, 0, 10, -10 ); doTest( 100L, 1, 11, -9 ); doTest( 101L, 1, 11, -9 ); doTest( 199L, 1, 11, -9 ); doTest( 200L, 2, 12, -8 ); } public void testOverflow() { doTest( 214748363700L, 2147483637, 2147483647, 2147483627 ); doTest( 214748363800L, 2147483638, -2147483648, 2147483628 ); doTest( 214748363900L, 2147483639, -2147483647, 2147483629 ); doTest( 214748364000L, 2147483640, -2147483646, 2147483630 ); doTest( 214748364100L, 2147483641, -2147483645, 2147483631 ); doTest( 214748364200L, 2147483642, -2147483644, 2147483632 ); doTest( 214748364300L, 2147483643, -2147483643, 2147483633 ); doTest( 214748364400L, 2147483644, -2147483642, 2147483634 ); doTest( 214748364500L, 2147483645, -2147483641, 2147483635 ); doTest( 214748364600L, 2147483646, -2147483640, 2147483636 ); doTest( 214748364700L, 2147483647, -2147483639, 2147483637 ); doTest( 214748364800L, -2147483648, -2147483638, 2147483638 ); doTest( 214748364900L, -2147483647, -2147483637, 2147483639 ); doTest( 214748365000L, -2147483646, -2147483636, 2147483640 ); doTest( 214748365100L, -2147483645, -2147483635, 2147483641 ); doTest( 214748365200L, -2147483644, -2147483634, 2147483642 ); doTest( 214748365300L, -2147483643, -2147483633, 2147483643 ); doTest( 214748365400L, -2147483642, -2147483632, 2147483644 ); doTest( 214748365500L, -2147483641, -2147483631, 2147483645 ); doTest( 214748365600L, -2147483640, -2147483630, 2147483646 ); doTest( 214748365700L, -2147483639, -2147483629, 2147483647 ); doTest( 214748365800L, -2147483638, -2147483628, -2147483648 ); doTest( 429496729300L, -3, 7, -13 ); doTest( 429496729400L, -2, 8, -12 ); doTest( 429496729500L, -1, 9, -11 ); doTest( 429496729600L, 0, 10, -10 ); doTest( 429496729700L, 1, 11, -9 ); doTest( 429496729800L, 2, 12, -8 ); doTest( 429496729900L, 3, 13, -7 ); } } ava.util.List; import java.util.ListIterator; import java.util.Arrays; public class WrapperPrintParam { public static void main( String[] args ) { System.out.println( "Dump all JVM parameters using RuntimeMXBean:" ); System.out.println( " (There is a bug in Java that was fixed in 1.7 which causes all parameters being displayed below to be split into different arguments when spaces are encountered.)" ); try { Class cRuntimeMXBean = Class.forName( "java.lang.management.RuntimeMXBean" ); Class cManagementFactory = Class.forName( "java.lang.management.ManagementFactory" ); Method mGetRuntimeMXBean = cManagementFactory.getMethod( "getRuntimeMXBean", null ); Method mGetInputArguments = cRuntimeMXBean.getMethod( "getInputArguments", null ); Object runtimemxBean = mGetRuntimeMXBean.invoke( null, ( Object[] ) null ); List jvm_args = ( List ) mGetInputArguments.invoke( runtimemxBean, ( Object[] ) null ); System.out.println( jvm_args.size() + " JVM Parameter(s):" ); for ( ListIterator i = jvm_args.listIterator(); i.hasNext(); ) { String arg = (String)i.next(); System.out.println( " " + arg ); } List app_args = Arrays.asList( args ); System.out.println( app_args.size() + " Application Parameter(s):" ); for ( ListIterator i = app_args.listIterator(); i.hasNext(); ) { String arg = ( String ) i.next(); System.out.println( " " + arg ); } System.out.println(); System.out.println( "Resulting System Properties:" ); for ( ListIterator i = jvm_args.listIterator(); i.hasNext(); ) { String arg = (String)i.next(); if ( arg.startsWith( "-D" ) ) { int pos = arg.indexOf( '=' ); if ( pos >= 0 ) { String name = arg.substring( 2, pos ); System.out.println( " " + name + "=" + System.getProperty( name ) ); } } } } catch ( ClassNotFoundException e ) { e.printStackTrace(); } catch ( IllegalArgumentException e ) { e.printStackTrace(); } catch ( IllegalAccessException e ) { e.printStackTrace(); } catch ( InvocationTargetException e ) { e.printStackTrace(); } catch ( SecurityException e ) { e.printStackTrace(); } catch ( NoSuchMethodException e ) { e.printStackTrace(); } } } wrapper_3.5.26_src/src/test/org/tanukisoftware/wrapper/WrapperManagerSystemTimeTestCase.java100644 0 0 11115 12440202301 27673 0ustar 0 0 package org.tanukisoftware.wrapper; /* * Copyright (c) 1999, 2014 Tanuki Software, Ltd. * http://www.tanukisoftware.com * All rights reserved. * * This software is the confidential and proprietary information * of Tanuki Software. ("Confidential Information"). You shall * not disclose such Confidential Information and shall use it * only in accordance with the terms of the license agreement you * entered into with Tanuki Software. */ import junit.framework.TestCase; /** * Tests the conversion of system time into ticks. * * @author Leif Mortenson */ public class WrapperManagerSystemTimeTestCase extends TestCase { private final int TICK_MS = 100; /*--------------------------------------------------------------- * Constructor *-------------------------------------------------------------*/ public WrapperManagerSystemTimeTestCase( String name ) { super( name ); } /*--------------------------------------------------------------- * Methods *-------------------------------------------------------------*/ private int getSystemTicks( long time ) { // Calculate a tick count using the current system time. The // conversion from a long in ms, to an int in TICK_MS increments // will result in data loss, but the loss of bits and resulting // overflow is expected and Ok. return (int)( time / TICK_MS ); } private long getTickAge( int start, int end ) { // Important to cast the first value so that negative values are correctly // cast to negative long values. return (long)( end - start ) * TICK_MS; } public void doTest( long time, int expectedTicks, int negTicks, int posTicks ) { int ticks = getSystemTicks( time ); assertEquals( "getSystemTicks( " + time + " ) failed", expectedTicks, ticks ); long posAge = getTickAge( posTicks, expectedTicks ); assertEquals( "getTickAge( " + posTicks + ", " + expectedTicks + " )", 1000L, posAge ); long negAge = getTickAge( negTicks, expectedTicks ); assertEquals( "getTickAge( " + negTicks + ", " + expectedTicks + " )", -1000L, negAge ); } /*--------------------------------------------------------------- * Test Cases *-------------------------------------------------------------*/ public void testSimple() { doTest( 0L, 0, 10, -10 ); doTest( 1L, 0, 10, -10 ); doTest( 2L, 0, 10, -10 ); doTest( 99L, 0, 10, -10 ); doTest( 100L, 1, 11, -9 ); doTest( 101L, 1, 11, -9 ); doTest( 199L, 1, 11, -9 ); doTest( 200L, 2, 12, -8 ); } public void testOverflow() { doTest( 214748363700L, 2147483637, 2147483647, 2147483627 ); doTest( 214748363800L, 2147483638, -2147483648, 2147483628 ); doTest( 214748363900L, 2147483639, -2147483647, 2147483629 ); doTest( 214748364000L, 2147483640, -2147483646, 2147483630 ); doTest( 214748364100L, 2147483641, -2147483645, 2147483631 ); doTest( 214748364200L, 2147483642, -2147483644, 2147483632 ); doTest( 214748364300L, 2147483643, -2147483643, 2147483633 ); doTest( 214748364400L, 2147483644, -2147483642, 2147483634 ); doTest( 214748364500L, 2147483645, -2147483641, 2147483635 ); doTest( 214748364600L, 2147483646, -2147483640, 2147483636 ); doTest( 214748364700L, 2147483647, -2147483639, 2147483637 ); doTest( 214748364800L, -2147483648, -2147483638, 2147483638 ); doTest( 214748364900L, -2147483647, -2147483637, 2147483639 ); doTest( 214748365000L, -2147483646, -2147483636, 2147483640 ); doTest( 214748365100L, -2147483645, -2147483635, 2147483641 ); doTest( 214748365200L, -2147483644, -2147483634, 2147483642 ); doTest( 214748365300L, -2147483643, -2147483633, 2147483643 ); doTest( 214748365400L, -2147483642, -2147483632, 2147483644 ); doTest( 214748365500L, -2147483641, -2147483631, 2147483645 ); doTest( 214748365600L, -2147483640, -2147483630, 2147483646 ); doTest( 214748365700L, -2147483639, -2147483629, 2147483647 ); doTest( 214748365800L, -2147483638, -2147483628, -2147483648 ); doTest( 429496729300L, -3, 7, -13 ); doTest( 429496729400L, -2, 8, -12 ); doTest( 429496729500L, -1, 9, -11 ); doTest( 429496729600L, 0, 10, -10 ); doTest( 429496729700L, 1, 11, -9 ); doTest( 429